相关推荐:
Thanks
类注释
IntentService is a base class for {@link Service}s that handle asynchronous
requests (expressed as {@link Intent}s) on demand. Clients send requests
through {@link android.content.Context#startService(Intent)} calls; the
service is started as needed, handles each Intent in turn using a worker
thread, and stops itself when it runs out of work.
IntentService 继承 Service ,客户端通过 android.content.Context#startService(Intent) 发送Intent给Service,Service便开始工作,他使用工作线程处理每一个Intent,并且自动结束生命周期在完成所有的工作后。
* <p>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),当他接收到意图的时候,会启动一个工作线程去处理意图,并停止服务当他完成的时候。
* <p>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: onStartCommand
15:09:23.987 8941-8959/com.chestnut.ui I/TestIntentService: action:Action_Sleep
15:09:24.848 8941-8941/com.chestnut.ui I/TestIntentService: onStartCommand
15:09:28.989 8941-8959/com.chestnut.ui I/TestIntentService: action, done
15:09:28.990 8941-8959/com.chestnut.ui I/TestIntentService: action:Action_Soon
15:09:28.990 8941-8959/com.chestnut.ui I/TestIntentService: action, done
15: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) {
}
}
再找到:mActivityManager.stopServiceToken:
@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号。
码字不易,方便的话素质三连,或者关注我的公众号 技术酱,专注 Android 技术,不定时推送新鲜文章,如果你有好的文章想和大家分享,欢迎关注投稿!