哎,最近刚刚开始做framework开发。主要做些BUG修改之类的。刚进公司。进项目组,由于之前不是做framework开发,所以很生疏。我接到的第一个任务就是移植工厂测试工具MMI.
好不容易移植到系统中去了以后呢。在各个测试项复查的过程中发现有几个case测试通不过。AlarmManager.setRepeating就是让我很头疼。我是想在一秒钟重复一次。但是始终不行,所以分析了一些源码,记录一下,以后好复习。
AlarmManager.setRepeating(int type, long triggerAtMillis, long intervalMillis, PendingIntent operation)这几个参数我就不对说了,可以参考http://blog.csdn.net/ricks_wu/article/details/22494015。比较详细。
我们使用的AlarmManager类其实是很简单的一个包装类。他在android.app下。
AlarmManager的成员函数有:
AlarmManager(IAlarmManager service)
publicvoid set(int type,long triggerAtTime, PendingIntent operation)
publicvoid setRepeating(int type,long triggerAtTime,long interval,
PendingIntent operation)
publicvoid setInexactRepeating(int type,long triggerAtTime,long interval,PendingIntent operation)
publicvoid cancel(PendingIntent operation)
publicvoid setTime(long millis)
publicvoid setTimeZone(String timeZone)
try {
mService.set(type, triggerAtMillis, windowMillis, intervalMillis, operation,
workSource, alarmClock);
} catch (RemoteException ex) {
}
对就是调用的<span style="font-family: consolas, 'Courier New', courier, monospace;">mService,那它是什么呢?</span><pre name="code" class="java">private final IAlarmManager mService;
继续跟踪会发现,它其实就是AlarmManagerService里面的IBind一个对象。熟悉IPC的就不会很生疏了,
class AlarmManagerService extends SystemService{、
<span style="white-space:pre"> </span>....
<span style="white-space:pre"></span><pre name="code" class="java"><span style="white-space:pre"> </span>private final IBinder mService = new IAlarmManager.Stub() {
@Override
public void set(int type, long triggerAtTime, long windowLength, long interval,
PendingIntent operation, WorkSource workSource,
AlarmManager.AlarmClockInfo alarmClock) {
if (workSource != null) {
getContext().enforceCallingPermission(
android.Manifest.permission.UPDATE_DEVICE_STATS,
"AlarmManager.set");
}
setImpl(type, triggerAtTime, windowLength, interval, operation,
windowLength == AlarmManager.WINDOW_EXACT, workSource, alarmClock);
}
@Override
public boolean setTime(long millis) {
}
@Override
public void setTimeZone(String tz) {
}
@Override
public void remove(PendingIntent operation) {
}
@Override
public AlarmManager.AlarmClockInfo getNextAlarmClock(int userId) {
}
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
}
@Override
public void updateBlockedUids(int uid, boolean isBlocked) {
}
};
<span style="white-space:pre"> </span>....
}
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,calendar.getTimeInMillis(), 1 * 1000,pendingIntent);
就会调用到这里的
AlarmManager:
public void setRepeating(int type, long triggerAtMillis,
long intervalMillis, PendingIntent operation) {
setImpl(type, triggerAtMillis, legacyExactLength(), intervalMillis, operation, null, null);
}
注意这里legacyExactLength(); 看看它:
<span style="white-space:pre"> </span>AlarmManager(IAlarmManager service, Context ctx) {
mService = service;
final int sdkVersion = ctx.getApplicationInfo().targetSdkVersion;
mAlwaysExact = (sdkVersion < Build.VERSION_CODES.KITKAT);//<span style="font-family: Arial, Helvetica, sans-serif;">Build.VERSION_CODES.KITKAT=19</span>
}
private long legacyExactLength() {
return (mAlwaysExact ? WINDOW_EXACT : WINDOW_HEURISTIC);//<span style="font-family: Arial, Helvetica, sans-serif;">WINDOW_EXACT=0;</span><span style="font-family: Arial, Helvetica, sans-serif;">WINDOW_HEURISTIC = -1;</span>
}
mAlwaysExact?是什么? 在AlarmManager 构造函数里面可以看到他。
这里是在比较版本。如果是在19以后则不能精确发生,在19之前可以做到时间精确提醒,说是为了节约使用电量,所以害得我在5.1手机上始终无法得到1秒钟唤醒一次。
接下来去到了
AlarmManagerService的<pre name="code" class="java" style="color: rgb(51, 51, 51); font-size: 13px; line-height: 23px;">IBinder mService了。
setImpl(type, triggerAtTime, windowLength, interval, operation,
windowLength == AlarmManager.WINDOW_EXACT, workSource, alarmClock); //<span style="font-family: Arial, Helvetica, sans-serif;">AlarmManager.WINDOW_EXACT =0</span>
注意这里第6个参数
windowLength == AlarmManager.WINDOW_EXACT
windowLength在19以后是-1 在19之前是0.
所以第六个参数是false.调用AlarmManagerService的setImpl方法如下:
void setImpl(int type, long triggerAtTime, long windowLength, long interval,
PendingIntent operation, boolean isStandalone, WorkSource workSource,
AlarmManager.AlarmClockInfo alarmClock) {
<pre name="code" class="java"><span style="white-space:pre"> </span>..........
// Sanity check the recurrence interval. This will catch people who supply // seconds when the API expects milliseconds. if (interval > 0 && interval < MIN_INTERVAL) {
<span style="white-space:pre"> </span>Slog.w(TAG, "Suspiciously short interval " + interval
+ " millis; expanding to " + (int)(MIN_INTERVAL/1000)
+ " seconds");
interval = MIN_INTERVAL;
}
<span style="white-space:pre"> </span>..........
}
// Minimum alarm recurrence interval
private static final long MIN_INTERVAL = 60 * 1000; // one minute, in millis
哇。就在这里处理了我的时间,如果重复的时间小于1一分钟。则设置为一分钟,难怪我始终1秒钟始终不行啊。。。。晕哦。
哎。搞里半天是这里的问题。如果我就是要在1S后执行呢,放心Google提供了一个新方法:setExact去实现精确的时间提醒。