关于Android消息机制的原理及Handler,MessageQueue,Looper的原理我们在之前有分析过,而HandlerThread则是Android对线程加入了Handler进行了封装处理的产物。而IntentService则是在Service基础上加入了HandlerThread的封装,今天就它们我们来分析下源码及各自使用的场景。
HandlerThread
HandlerThread是一种自带Looper的线程,Looper在创建线程的时候就会自动产生,HandlerThread自己会维护自己的一个消息队列。通过HandlerThread中的Looper创建出Handler,通过这个Handler就可以向HandlerThread中发送要执行的任务,因为创建的HandlerThread为非主线程(子线程),所以执行的是一种异步任务。同时因为HandlerThread拥有自己的消息队列,发送的任务也会被依次添加到该消息队列中,所以HandlerThread同时是顺序的执行异步任务。下面就以上特点,我们通过源码分析来验证。
HandlerThread源码很简单,我们可以通过使用它的顺序来分析。首先使用的时候需要先调用start()启动线程,然后通过Looper构造Handler,然后通过Handler发送任务到HandlerThread中。而线程调用start()创建线程之后会调用run()执行,所以我们首先来看下run()函数。
@Override
public void run() {
mTid = Process.myTid();
// 首先创建HandlerThread线程的Looper
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
// 设置线程优先级
Process.setThreadPriority(mPriority);
// Looper启动前的准备工作
onLooperPrepared();
// 开始Looper循环。
Looper.loop();
mTid = -1;
}
在run()方法中,首先通过Looper.prepare()来创建Looper,然后设置完线程的优先级之后及Looper启动前的准备工作之后就调用Looper.loop()开始启动Looper处理消息队列中的消息了。这里的onLooperPrepared()是一个保护函数,可重写它来完成一些loop()前的操作。
在消息队列启动之后,我们就可以通过线程中的Looper()来创建Handler了,在Android消息机制中我们有分析知道,Handler工作在其创建它的线程中,所以Handler是在HandlerThread中处理消息。而HandlerThread又是一个子线程,同时该子线程中也创建了Looper并执行了loop(),所以印证了开头所说,HandlerThread是一种顺序执行(串行执行)异步任务的Thread。所以如果某一个任务执行时间过长,那么就会导致之后的任务相对应的被延迟。
最后,需要注意的一点就是,当HandlerThread使用完之后,因为子线程中的Looper一直不断地在loop(),所以我们需要及时的使用quit()或者quitSafely()进行退出。两者区别是quit()将会立即退出消息队列,不会再处理消息队列中的延迟消息(postDelay发送的消息)和非延迟消息,而quitSafely()则是会处理消息队列中的消息,然后再退出消息队列。
IntentService
IntentService是一个抽象类,使用时需要自定义一个类来继承它。它继承于Service,并且内部自带HandlerThread,用于在Service中处理异步任务。自定义IntentService时,需要重写onHandleIntent(),该方法在HandlerThread(子线程)中执行。然后通过startService()来启动服务。我们先来看下IntentService创建时执行的onCreate()方法。
@Override
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。
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
// 然后启动HandlerThread线程。
thread.start();
mServiceLooper = thread.getLooper();
// 创建Handler,用来将数据发送到HandlerThread线程中的任务执行。
mServiceHandler = new ServiceHandler(mServiceLooper);
}
在创建IntentService时,会创建HandlerThread并启动,同时会根据HandlerThread的looper来创建一个类内部定义的Handler,这个在HandlerThread线程中执行的Handler是怎么处理任务的呢,我们再来看下类内部定义的ServiceHandler。
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);
}
}
......
// 需要重写的抽象函数,在这个函数中执行需要处理的任务
protected abstract void onHandleIntent(@Nullable Intent intent);
ServiceHandler接收到消息时会先调用IntentService必须要重写的函数onHandleIntent()来执行任务,执行完任务之后便会调用stopSelf()来停止服务,无需用户手动关闭。
知道了IntentService是如何来执行任务的,现在我们需要了解哪里触发了ServiceHandler来发送消息。在Service中我们知道当我们调用了startService()之后便会触发服务的onStartCommand()。同理,我们来IntentService的onStartCommand()函数。
/** 注释中也要求你使用IntentService时候需要重写 onHandleIntent()方法。
* 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;
}
onStartCommand()函数中将我们传入的Intent传入了onStart()函数。
@Override
public void onStart(@Nullable Intent intent, int startId) {
// ServiceHandler发送消息去执行任务
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
可以看到,当调用startService()的时候触发onStartCommand(),然后在onStart()中ServiceHandler类型的handler会将Intent封装到message中发送,触发之前ServiceHandler中的handleMessage(),最终触发onHandleIntent()来执行任务。
所以,使用IntentService时需要先自定义一个类继承它,然后重写抽象函数onHandleIntent()(任务逻辑在其中执行),通过调用startService来触发ServiceHandler类型的handler发送消息给HandlerThread中的消息队列,所以onHandleIntent()会在子线程HandlerThread中执行,在任务执行完之后会自动调用stopSelf()停止服务。
实现Demo
实现demo GitHub传送门
总结
-
HandlerThread通过继承Thread,在子线程中会创建Looper并开启自己线程的消息队列,通过handler将任务发送到HandlerThread在子线程中执行,并且由于维护了自己的消息队列,所以执行任务是串行执行的。使用HandlerThread可以避免多开线程来执行多个任务,可通过handler不断发送任务到HandlerThread中执行。所以如果有任务耗时过长,就会导致后续任务执行的延迟。 -
IntentService继承于Service,内部含有HandlerThread来处理任务。Service本身执行在主线程中,由于自带了HandlerThread,所以任务执行在子线程中,并且可以通过多次调用startService来多次执行任务。并且IntentService在每次执行完任务之后会自动停止服务,所以也无需用户手动停止。