【frameworks/base/core/java/android/app/IntentService.java】
@Override
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
可以看到,IntentService创建伊始就会启动一个消息泵线程HandlerThread,然后又创建了一个可以向这个消息泵线程传递消息的Handler(即ServiceHandler)。
ServiceHandler是IntentService的一个内嵌类,其定义如下:
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1); // 注意,不是stopService()!
}
}
在紧随onCreate()函数之后,系统会调用到onStartCommand()函数,这个大家都很熟悉了。对于startService()动作而言,系统只会在service尚不存在的情况下,创建相应的service,并回调其onCreate()函数。以后,只要这个service没有被销毁,就不会重复再调用onCreate()了。不过,每次调用startService()都会导致走到onStartCommand()函数。IntentService的onStartCommand()函数的代码如下:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
在IntentService.java文件里,onHandleIntent()只是做了简单的声明:
protected abstract void onHandleIntent(Intent intent);
其具体行为要看我们写的IntentService派生类怎么定义这个函数啦。
【frameworks/base/core/java/android/app/Service.java】
public final void stopSelf(int startId) {
if (mActivityManager == null) {
return;
}
try {
mActivityManager.stopServiceToken(
new ComponentName(this, mClassName), mToken, startId);
} catch (RemoteException ex) {
}
}
请大家注意那个startId参数,这个参数是系统通过onStartCommand()传递给service的,也就是前文我们打伏笔的地方。要了解这个startId参数,我们得看一下AMS里的相关代码。
【frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java】
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, int userId) {
. . . . . .
. . . . . .
ComponentName res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid, userId);
. . . . . .
. . . . . .
}
【frameworks/base/services/core/java/com/android/server/am/ActiveServices.java】
ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType,
int callingPid, int callingUid, int userId) {
. . . . . .
ServiceRecord r = res.record;
. . . . . .
r.lastActivity = SystemClock.uptimeMillis();
r.startRequested = true;
r.delayedStop = false;
r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
service, neededGrants)); // 注意这里的r.makeNextStartId()
. . . . . .
. . . . . .
return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
也就是说,每当我们调用startService()启动一个服务时,不但会在其对应的ServiceRecord节点的pendingStarts里插入一个新的StartItem节点,而且会为这个StartItem节点生成一个新的id号,这个id号就是日后的startId啦。
【frameworks/base/services/core/java/com/android/server/am/ServiceRecord.java】
public int makeNextStartId() {
lastStartId++;
if (lastStartId < 1) {
lastStartId = 1;
}
return lastStartId;
}
当onStartCommand()向消息泵线程打入消息时,startId就被记录进message里了。我们现在举个例子,假设几乎在同时有两个地方都调用startService()来启动同一个IntentService,此时很可能会形成两个StartItem和两个IntentService消息,画出示意图如下,图中以msg1为基准,绘制了逻辑上的执行路径,请大家注意图中的逻辑序号。
既然消息队列里的消息已经和AMS里的StartItem对应上了,那么在处理完消息后,调用stopSelf()时,应该也必须考虑到这种匹配关系。所以stopSelf()的参数就是startId。前文我们已经看到,stopSelf()内部是在调用:
mActivityManager.stopServiceToken(
new ComponentName(this, mClassName), mToken, startId);
【frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java】
@Override
public boolean stopServiceToken(ComponentName className, IBinder token,
int startId) {
synchronized(this) {
return mServices.stopServiceTokenLocked(className, token, startId);
}
}
【frameworks/base/services/core/java/com/android/server/am/ActiveServices.java】
boolean stopServiceTokenLocked(ComponentName className, IBinder token, int startId) {
. . . . . .
ServiceRecord r = findServiceLocked(className, token, UserHandle.getCallingUserId());
if (r != null) {
if (startId >= 0) {
ServiceRecord.StartItem si = r.findDeliveredStart(startId, false);
if (si != null) {
// 用while循环删除位于startId对应的StartItem节点以及其之前的所有节点
while (r.deliveredStarts.size() > 0) {
ServiceRecord.StartItem cur = r.deliveredStarts.remove(0);
cur.removeUriPermissionsLocked();
if (cur == si) {
break;
}
}
}
if (r.getLastStartId() != startId) {
return false; // 如果不是最后一个startItem节点,则直接return false了
}
if (r.deliveredStarts.size() > 0) {
Slog.w(TAG, "stopServiceToken startId " + startId
+ " is last, but have " + r.deliveredStarts.size()
+ " remaining args");
}
}
. . . . . .
// 当最后一个startItem摘掉后,才真正结束service
bringDownServiceIfNeededLocked(r, false, false);
. . . . . .
return true;
}
return false;
}
【frameworks/base/core/java/android/app/IntentService.java】
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
一般,我们可以在实现IntentService派生类时,在构造函数里调用这个函数。这里设置的mRedelivery成员会在onStartCommand()函数里影响最终的返回值,从而影响service的“重递送intent”的行为。
我们再列一次onStartCommand()的代码:
public int onStartCommand(Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
当mRedelivery为true,会返回START_REDELIVER_INTENT,这个值的意思是说,如果在onStartCommand()之后的某个时刻,该service对应的进程被kill了,那么系统会自动重启该service,并向onStartCommand()重新传入当初startService()时指定的intent。另外,在极端情况下,可能已经有多个地方startService()了,那么系统在重启service之后,应该会将自己记录的多个intent逐条传递回service,也就是说,有可能会执行多次onStartCommand()了。而当mRedelivery为false时,会返回START_NOT_STICKY,它表示如果在后续某个时刻,该service对应的进程被kill了,系统是不会自动重启该service的。
有关IntentService的知识,我们就先说这么多,有兴趣的同学不妨对比代码看看。