本文是对Android IntentService的源码解析,对其基本使用还不了解的朋友可以先快速入门IntentService再来阅读本文。
类似于Activity,Service也有onCreate、onDestory等用于管理生命周期的方法,先来看看IntentService初始化的源码。
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
@Override
public void onCreate() {
super.onCreate();
//1
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
//2
mServiceLooper = thread.getLooper();
//3
mServiceHandler = new ServiceHandler(mServiceLooper);
}
IntentService是串行处理任务的,说到串行处理,Handler就是最典型的例子。从源码可以看出IntentService也用到了Handler。这里简单说一下Handler,Handler由如下几个部分组成。
HandlerThread:特殊的线程类,自带Looper,Handler必须运行在一个有Looper的线程上。
Looper:内部维护着一个消息队列,串行地取出消息进行处理。Looper是线程局部变量,也就是说每个HandlerThread都有属于自己的Looper(通过ThreadLocal来实现)。
Message:用于装载消息,消息传递完以后可以被Looper回收再利用(回收到Message池)。
MessageQueue:收到的消息在此排队等待Looper来处理。
对Handler源码感兴趣的朋友可以看看我写的这篇文章。回到刚刚的源码,代码1先创建一个HandlerThread,这个线程就是IntentService处理请求的线程。代码2获取这个线程的Looper。代码3完成Handler初始化。
完成了初始化操作,IntentService就可以来处理请求了。前面说到IntentService是通过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);
}
}
ServiceHandler的源码很简单,我们重写的onHandleIntent方法就是在handleMessage方法里调用的。处理完请求就尝试停止Service。也就是说调用stopSelf方法Service不一定会立刻停止。这里需要结合另外两个方法来解释。
@Override
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
//1
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
//2
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
看到代码1,刚刚stopSelf方法传入的startId就是来自这里。stopSelf方法会判断传入的startId和onStartCommand的startId是否相同。相同就停止服务,不相同就暂时不停止它。
现在把onStartCommand的startId记为A,把stopSelf传入的startId记为B。A不等于B说明在任务1完成前,任务2请求就来了,如果完成了任务1立即停止服务,任务2的请求就不能得到处理了。同理,A等于B说明任务1完成时还没有新的任务请求发过来,这时立即停止服务并不会有什么不妥,新的任务请求发来了再重新启动服务就可以了,
如此一来,IntentService就实现了自动停止的功能。接下来再看看服务停止时做了什么。
//IntentService.java
@Override
public void onDestroy() {
mServiceLooper.quit();
}
//Looper.java
public void quit() {
mQueue.quit(false);
}
销毁服务的操作很简单,让Looper停下来就可以了,这里Looper是非安全退出,也就是说,队列里的任务会被取消掉。调用stopSelf(-1)不需要等所有的任务处理完,可以直接停止服务。
IntentService有这么一个方法,它可以让Intent实现重传。
/**
* Sets intent redelivery preferences. Usually called from the constructor
* with your preferred semantics.
*
* If enabled is true,
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_REDELIVER_INTENT}, so if this process dies before
* {@link #onHandleIntent(Intent)} returns, the process will be restarted
* and the intent redelivered. If multiple Intents have been sent, only
* the most recent one is guaranteed to be redelivered.
*
*
If enabled is false (the default),
* {@link #onStartCommand(Intent, int, int)} will return
* {@link Service#START_NOT_STICKY}, and if the process dies, the Intent
* dies along with it.
*/
public void setIntentRedelivery(boolean enabled) {
mRedelivery = enabled;
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
注释里意思是说如果setIntentRedelivery方法传入true,那么在进程被杀死的时候,Intent会被保存下来,等进程重启了再重新发送这个Intent。但是,对于多个Intent只有那个最新的Intent能够重传。其实这是通过onStartCommand方法的返回值来实现的。
https://www.jianshu.com/p/5c1fae2794f6
https://blog.csdn.net/mingli198611/article/details/8782772
https://www.jianshu.com/p/63a644166013