Thanks
类注释
IntentService is a base class for {@link Service}s that handle asynchronousrequests (expressed as {@link Intent}s) on demand. Clients send requeststhrough {@link android.content.Context#startService(Intent)} calls; theservice is started as needed, handles each Intent in turn using a workerthread, and stops itself when it runs out of work.复制代码
IntentService 继承 Service ,客户端通过 android.content.Context#startService(Intent) 发送Intent给Service,Service便开始工作,他使用工作线程处理每一个Intent,并且自动结束生命周期在完成所有的工作后。
*This "work queue processor" pattern is commonly used to offload tasks * from an application's main thread. The IntentService class exists to * simplify this pattern and take care of the mechanics. To use it, extend * IntentService and implement {@link #onHandleIntent(Intent)}. IntentService * will receive the Intents, launch a worker thread, and stop the service as * appropriate.复制代码
工作线程采用队列的机制,队列通常接受来自于主线程的任务。IntentService 简化了这种处理机制,为了使用它,你需要实现 onHandleIntent(Intent),当他接收到意图的时候,会启动一个工作线程去处理意图,并停止服务当他完成的时候。
*All requests are handled on a single worker thread -- they may take as* long as necessary (and will not block the application's main loop), but* only one request will be processed at a time.复制代码
所有的请求都在同一个工作线程去处理,也许会需要比较长的时间(但不会阻塞UI线程),但同一个时刻只会有同一个的请求在处理。
初始化HandlerThread & Handler
public void onCreate() { super.onCreate(); HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); thread.start(); mServiceLooper = thread.getLooper(); mServiceHandler = new ServiceHandler(mServiceLooper);}复制代码
在onCreate中初始化HandlerThread,其里面有已经集成好了Loop,所以,IntentService的核心是基于子线程的一个Handler消息处理机制,所以看到有一个ServiceHandler的自定义Handler处理类:
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); }}复制代码
在上面看到,在handlerMessage,回调:onHandlerIntent,这个方法需要我们外部去实现,当然,此方法明显是在工作线程中回调,而且回调完这个方法后,自动调用了stopSelf来停止服务。
protected abstract void onHandleIntent(@Nullable Intent intent);复制代码
setIntentRedelivery
设置意图是否重新发送,描述在service的onStartCommand调用后,被系统杀死,是否重新发送未完成的意图。
public void setIntentRedelivery(boolean enabled) { mRedelivery = enabled;}复制代码
public int onStartCommand(@Nullable Intent intent, int flags, int startId) { onStart(intent, startId); return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;}复制代码
设置true返回START_REDELIVER_INTENT:表示在系统杀死后,会被重启启动,送入未完成发送的Intent,如果都完成了,则送入最近一个Intent重启服务。设置false返回START_NOT_STICKY,则被杀死后,不会自动重启。
当然,onStartCommand在原生系统上是生效的,但是在国产ROM,可能都失效了吧,毕竟这有点流氓。
一个疑问
在ServiceHandler的handlerMessage方法内部,消息处理完成后就stopSelf,那么在处理前一个消息时,调用的stopSelf()不是把service结束了吗?那它还怎么保证继续处理后续消息呢?
我们通过代码重现一下上面的疑问,假如有这样的一个Service: TestIntentService
public class TestIntentService extends IntentService { private final static String TAG = "TestIntentService"; public final static String Action_Sleep = "Action_Sleep"; public final static String Action_Soon = "Action_Soon"; @Override public int onStartCommand(@Nullable Intent intent, int flags, int startId) { LogUtils.i(TAG,"onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override protected void onHandleIntent(@Nullable Intent intent) { LogUtils.i(TAG, intent==null ? "null intent" : "action:" + intent.getAction()); if (intent!=null && intent.getAction()!=null) { switch (intent.getAction()) { case Action_Sleep: try { Thread.sleep(5*1000); } catch (InterruptedException e) { e.printStackTrace(); } break; case Action_Soon: break; } } } @Override public void onDestroy() { LogUtils.i(TAG,"onDestroy"); super.onDestroy(); }}复制代码
定义了两个Action,一个模拟阻塞。
findViewById(R.id.btn_1).setOnClickListener(v -> { Intent intent = new Intent(this, TestIntentService.class); intent.setAction(TestIntentService.Action_Sleep); startService(intent);});findViewById(R.id.btn_2).setOnClickListener(v -> { Intent intent = new Intent(this, TestIntentService.class); intent.setAction(TestIntentService.Action_Soon); startService(intent);});复制代码
然后,点击完btn_1后立即点击btn_2,日志如下:
15:09:23.985 8941-8941/com.chestnut.ui I/TestIntentService: onStartCommand15:09:23.987 8941-8959/com.chestnut.ui I/TestIntentService: action:Action_Sleep15:09:24.848 8941-8941/com.chestnut.ui I/TestIntentService: onStartCommand15:09:28.989 8941-8959/com.chestnut.ui I/TestIntentService: action, done15:09:28.990 8941-8959/com.chestnut.ui I/TestIntentService: action:Action_Soon15:09:28.990 8941-8959/com.chestnut.ui I/TestIntentService: action, done15:09:28.991 8941-8941/com.chestnut.ui I/TestIntentService: onDestroy复制代码
从上面日志看到,阻塞的时候,收到一个第二个Intent请求,此时不会立即处理,而是等之前的Intent请求处理完成,前一个intent处理完成,调用stopself,但并不会立即结束service,是在所有的intent处理完成后,才结束service,可是为啥呢?我们从源码中分析一下:
先看stopSelf()
stopSelf()位于Service.java:
public final void stopSelf(int startId) { if (mActivityManager == null) { return; } try { mActivityManager.stopServiceToken( new ComponentName(this, mClassName), mToken, startId); } catch (RemoteException ex) { }}复制代码
再找到::
@Override public boolean stopServiceToken(ComponentName className, IBinder token, int startId) { synchronized(this) { return mServices.stopServiceTokenLocked(className, token, startId); } }复制代码
mServices是mServices = new ActiveServices(this)
,mServices.stopServiceTokenLocked如下:
boolean stopServiceTokenLocked(ComponentName className, IBinder token, int startId) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "stopServiceToken: " + className + " " + token + " startId=" + startId); //找出对应的Service记录器 ServiceRecord r = findServiceLocked(className, token, UserHandle.getCallingUserId()); if (r != null) { if (startId >= 0) { // Asked to only stop if done with all work. Note that // to avoid leaks, we will take this as dropping all // start items up to and including this one. ServiceRecord.StartItem si = r.findDeliveredStart(startId, false, false); if (si != null) { while (r.deliveredStarts.size() > 0) { ServiceRecord.StartItem cur = r.deliveredStarts.remove(0); cur.removeUriPermissionsLocked(); if (cur == si) { break; } } } //在这里,如果说,当前要结束的startId不等于最后一个ID,说明, //有其他的intent进来想要启动service,这种情况下,就会直接返回 //返回后,也就不停止service。 if (r.getLastStartId() != startId) { return false; } if (r.deliveredStarts.size() > 0) { Slog.w(TAG, "stopServiceToken startId " + startId + " is last, but have " + r.deliveredStarts.size() + " remaining args"); } } synchronized (r.stats.getBatteryStats()) { r.stats.stopRunningLocked(); } r.startRequested = false; if (r.tracker != null) { r.tracker.setStarted(false, mAm.mProcessStats.getMemFactorLocked(), SystemClock.uptimeMillis()); } r.callStart = false; final long origId = Binder.clearCallingIdentity(); bringDownServiceIfNeededLocked(r, false, false); Binder.restoreCallingIdentity(origId); return true; } return false; }复制代码
这段代码的主要意思还是比较明确的,那就是按序从ServiceRecord的deliveredStarts列表中删除StartItem节点,直到所删除的是startId参数对应的StartItem节点,如果此时尚未抵达ServiceRecord内部记录的最后一个start Id号,则说明此次stopSelf()操作没必要进一步结束service,那么直接return false就可以了。只有在所删除的startItem节点的确是最后一个startItem节点时,才会调用bringDownServiceIfNeededLocked()去结束service。这就是为什么IntentService的ServiceHandler在处理完消息后,可以放心调用stopSelf()的原因。
ServiceRecord是记录着正在运行服务的一些信息。而,ServiceRecord.StartItem 是每调用一次startService方法,就会生成一个Item对象:
ActivityManagerService.java
public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, int userId) { . . . . . . . . . . . . ComponentName res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, userId); . . . . . . . . . . . .}复制代码
ActiveServices.java
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, int userId) { . . . . . . //获取到对应的service记录器 ServiceRecord r = res.record; . . . . . . r.startRequested = true; r.delayedStop = false; //添加 startItem r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(), service, neededGrants)); . . . . . . . . . . . . return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);}复制代码
由上可见,在每一次startService的时候,都会新建一个startItem,并添加到ServiceRecord中记录起来,其中的一个makeNextStartId就是我们service回调方法中的startId,一个ID号。