使用过IntentService的都清楚,这是一个继承自Service,内部实现了HandlerThread来进行异步处理任务。因为Service默认是运行在主线程的,通过内部启动一个HandlerThread,和一个关联了该thread的handler来将该service得到的intent放入到线程中执行。我们实现时候,创建一个继承自IntentService的类,只需要实现其中的onHandleIntent(intent)方法,对拿到的intent做处理,该方法默认是在一个工作线程中执行的,执行完成后会自动销毁service。
IntentService就是方便我们在后台做异步任务使用的。
网上很多文章都说,intentService能够顺序的执行多个任务,这怎么理解呢?按照原来的理解执行完onHandleIntent方法后不就应该销毁了么,难道会一直等待任务,如果是等待的话,这个时间是多久呢?不可能一直等着不销毁吧,这不符合intentService的定义。究竟是怎么一回事,我们还得从源码里捋一捋。
首先我们看下类的定义:
public abstract class IntentService extends Service
是一个继承自Service的抽象类,其中只有一个抽象方法:
/**
* This method is invoked on the worker thread with a request to process.
* Only one Intent is processed at a time, but the processing happens on a
* worker thread that runs independently from other application logic.
* So, if this code takes a long time, it will hold up other requests to
* the same IntentService, but it will not hold up anything else.
* When all requests have been handled, the IntentService stops itself,
* so you should not call {@link #stopSelf}.
*
* @param intent The value passed to {@link
* android.content.Context#startService(Intent)}.
* This may be null if the service is being restarted after
* its process has gone away; see
* {@link android.app.Service#onStartCommand}
* for details.
*/
@WorkerThread
protected abstract void onHandleIntent(@Nullable Intent intent);
并且这个抽象方法是运行在工作线程的,我们继承IntentService的时候就要实现它。
另外该类的onBind方法是放回空的:
public IBinder onBind(Intent intent) {
return null;
}
所以限定了我们只能以startService的方法来启动这个service。(当然用bind的方法也是可以的,这就需要我们自己实现onBind方法了,但是这样做的话,intentService就没啥用处了,直接继承Service就好了)。
一般我们在activity中执行startService后,service执行的流程是onCreate,onStartCommand。所以我们先来看下onCreate方法内部干了啥:
public void onCreate() {
// TODO: It would be nice to have an option to hold a partial wakelock
// during processing, and to have a static startService(Context, Intent)
// method that would launch the service & hand off a wakelock.
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start(); // 开启了一个线程
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper); // 创建一个关联到上面线程的handler
}
就做了两件事:
1,使用HandlerThread开启一个线程
2,创建一个关联了该线程的mServiceHandler对象,这样我们使用这个mServiceHandler发送一个消息的时候,会把消息放入线程的消息队列中,然后通过线程中的looper对象不断的取消息队列中的消息,取到之后回调mServiceHandler的handleMessage来处理消息。这个消息处理的模型我们是不是很熟悉,对的,它就是UI线程消息处理的模型,只不过现在这个消息的接收和分发都放到了工作线程中来处理。
总结来说,就是在service的onCreate中,创建了handler的消息模型,该消息模型运行在一个工作线程中,静静的等待着我们发消息,然后处理消息。。。
接下来我们看看service生命周期的第二个方法,onStartCommand:
/**
* You should not override this method for your IntentService. Instead,
* override {@link #onHandleIntent}, which the system calls when the IntentService
* receives a start request.
* @see android.app.Service#onStartCommand
*/
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
onStart(intent, startId);
return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
}
直接调用了onStart方法:
public void onStart(@Nullable Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage(); // onCreate中创建的handler出现了,从msg池中复用取出一个msg
msg.arg1 = startId; // 记录startId,这个很关键,在后面的分析中会有意想不到的作用
msg.obj = intent; // 保存intent
mServiceHandler.sendMessage(msg); // 发送消息到工作线程的消息队列中
}
这里也是非常简单呢,用一个msg记录了启动的intent和一个startId,这个startId是当我们每次startService的时候,系统为我们分配的id,用来区别是哪次startService。我们在学习service的知道,startService是可以多次调用的,每调用一次就会回调一次onStartCommand方法。
从这个方法中我们知道,这里是将获取到的intent和startid通过handler发送到工作线程中的消息队列中,这个方法的执行还是在主线程(UI线程)。既然这里有发送消息,那么必然后处理消息啊。我们知道handler处理消息是在handleMessage方法中,所以我们要看看mServiceHandler这个对象的handleMessage做了啥:
通过onCreate方法的分析,我们知道在这里面创建了一个mServiceHandler对象,该对象是一个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);
}
}
其中的handleMessage是我们要重点关注的,在这个方法里面做了两个事情:
1,调用intentService的onHandlerIntent方法将msg携带的intent传进去,这个方式是我们继承的时候自己处理的。
2,执行完onHandleIntent后,执行停止service的方法。
乍一看,这里执行完了stopSelf后,service不是应该就被停止了么?不一定,玄机就在于这个方法。
关于这个方法,有两个重载,一个是无参的,一个是有参的,其中无参的方法调用的是有参的方法,并且传入startId为-1:
/**
* Stop the service, if it was previously started. This is the same as
* calling {@link android.content.Context#stopService} for this particular service.
*
* @see #stopSelfResult(int)
*/
public final void stopSelf() {
stopSelf(-1);
}
/**
* Old version of {@link #stopSelfResult} that doesn't return a result.
*
* @see #stopSelfResult
*/
public final void stopSelf(int startId) {
if (mActivityManager == null) {
return;
}
try {
mActivityManager.stopServiceToken(
new ComponentName(this, mClassName), mToken, startId);
} catch (RemoteException ex) {
}
}
内部是调用了AMS的stopService的流程。service的生命周期是AMS管理的,在调用stopSelf(int startId)的过程中,系统会检测是否还有startId存在,如果存在,则不销毁service,否则销毁service。当然如果你直接调用stopSelf(-1),那么将直接销毁service,系统就不会检测是否还有其他的startId存在。这个startId就是我们在onStartCommand中被分配的参数,系统为每一次的startService都分配了一个id。
所以即便我们在handleMessage中执行了stopSelf也不一定会立马结束service,这要看系统中是否还存在startid。
通过以上分析,我们可以知道在IntentService中顺序执行任务是啥意思?因为用的是消息队列,遵循先进先出的逻辑,所以保证了是顺序执行的;然后,什么是多个任务呢?就是多次启动了startService,每启动一次算一个任务msg入队。
其实要保证顺序执行完所有任务再退出service是有个前提的,就是在某个任务执行stopSelf前,必须有任务加入到了消息队列中(即startService)。如果我们每个任务开启的时间间隔过长,即每次startService间隔过长(具体时间长度依赖onHandlerIntent的执行时间),service将每次都会执行onDestroy,然后再执行onCreate,然后在onDestroy。。。
举个例子,假如onHandlerIntent的执行时间是5s,每次启动这个service的时间间隔是3s,那么第一次执行startService的时候,该service会依次执行onCreate,onStartCommand,然后onHandlerIntent,在执行onHandlerIntent的过程中,假如此时执行了3s,这时第二次执行startService,这个时候会执行service的onStartCommand,mServiceHandler将intent和startid包装成msg入消息队列,等待被执行。onHandlerIntent继续执行2s后,就到了stopSelf这里,系统检测出有新的startid(也就是我们第二次startService时候系统分配的startid),不会执行service的销毁,这个时候消息handler的handleMessage方法执行完了,然后继续从消息队列中取出第二次startService时候得到的intent执行,这样反复循环知道消息。
假如onHandlerIntent的执行时间还是5s,但是每次启动service的时间间隔是10s,那么必然执行完第一次startService后,处理完onHandlerIntent的业务后,系统就会去销毁service了。
结论:所谓的intentService顺序执行完所有任务再进行销毁,前提是在执行某个stopSelf的时候,当前系统检测到还有startid存在,即startService被及时调用,否则将会按照service正常的生命周期结束自己。保证顺序执行完所有任务的核心就是handler的模型和AMS对service的管理。
最后,贴一下两种测试的日志:
第一种假设,startService时间间隔较短,等到处理完所有的startService的intent后才执行onDestroy:
2019-04-17 19:30:23.960 3848-3848/com.txt.mydemo E/IntentServiceTestActivity: startService
2019-04-17 19:30:23.986 3848-9664/com.txt.mydemo I/myIntentService: onHandleIntent
2019-04-17 19:30:24.192 3848-3848/com.txt.mydemo E/IntentServiceTestActivity: startService
2019-04-17 19:30:25.989 3848-9664/com.txt.mydemo I/myIntentService: 滞后2s---->null
2019-04-17 19:30:25.994 3848-9664/com.txt.mydemo I/myIntentService: onHandleIntent
2019-04-17 19:30:27.997 3848-9664/com.txt.mydemo I/myIntentService: 滞后2s---->null
2019-04-17 19:30:28.002 3848-3848/com.txt.mydemo I/myIntentService: onDestroy
第二种假设,startService时间间隔较长,会按照正常的生命周期来执行:
2019-04-17 19:32:49.562 3848-3848/com.txt.mydemo E/IntentServiceTestActivity: startService
2019-04-17 19:32:49.585 3848-9723/com.txt.mydemo I/myIntentService: onHandleIntent
2019-04-17 19:32:51.587 3848-9723/com.txt.mydemo I/myIntentService: 滞后2s---->null
2019-04-17 19:32:51.593 3848-3848/com.txt.mydemo I/myIntentService: onDestroy
2019-04-17 19:32:52.451 3848-3848/com.txt.mydemo E/IntentServiceTestActivity: startService
2019-04-17 19:32:52.470 3848-9724/com.txt.mydemo I/myIntentService: onHandleIntent
2019-04-17 19:32:54.472 3848-9724/com.txt.mydemo I/myIntentService: 滞后2s---->null
2019-04-17 19:32:54.479 3848-3848/com.txt.mydemo I/myIntentService: onDestroy