HandlerThread和IntentService

为什么要把HandlerThread和IntentService放在一起说呢?因为这两个类的关系紧密。

HandlerThread到底是什么?

一句话就是:有消息循环的Thread就是HandlerThread。

HandlerThread的作用就是不断的从消息队列中取出Message,然后在当前线程执行。

HandlerThread的实现原理

其实HandlerThread的源代码非常简单,只有150行左右。

当我们在使用HandlerThread的时候,我们一般需要按照下面的步骤:

private Handler mHandler ;
private Handler.Callback mCallback = new Handler.Callback() {
    @Override
    public boolean handleMessage(Message msg) {
        return false;
    }
};

public void  initHanlderThread(){
    HandlerThread workHandle = new HandlerThread("workHandleThread");
    workHandle.start();
    mHandler = new Handler(workHandle.getLooper(), mCallback);
}

之后使用mHandler.postXXX()就可以将任务发送至HandlerThread执行了。

HandlerThread继承自Thread,当执行start()的时候,run()就会调用,在这里实现了消息队列的创建:

public class HandlerThread extends Thread {

    Looper mLooper;

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

     public Looper getLooper() {
        if (!isAlive()) {
            return null;
        }

        // If the thread has been started, wait until the looper has been created.
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
}

可以看到,在run()里面完成了Looper消息队列的创建,所以在实例化Handler的时候,Handler就会与HandlerThread线程的Looper进行关联,由Handler发送的Message最终会在Looper里面进行分发和执行。

同时,为了保证Looper一定可以初始化,这里使用wait()和notifyAll()进行了线程同步操作,需要注意的是,wait()阻塞的并不是HandlerThread的线程,而是调用getLooper()所在的线程,在这里指的就是UI线程,虽然有可能阻塞UI线程,但是正常情况下这里的操作没有什么危险。

通过简单的查看HandlerThread源码,我们可以很清楚HandlerThread的实现原理。

在什么时候用HandlerThread?

如果要想知道什么时候应该用HandlerThread,那么我们应该先总结一下HandlerThread的特点:

  • 是一个线程

  • 拥有Handler机制下消息循环

  • 由于基于是Handler机制,所以所有的消息处理都是串行的

有了这些特点,我们就不难知道HandlerThread在什么情况下使用比较合适了。

  • UI线程实际上就是一个HandlerThread,所有View的操作都是在消息循环里面处理的,如果在UI线程里面做耗时操作,比如大文件读取,就会阻塞消息队列,造成ANR,这也是为什么我们不能在UI线程中进行耗时工作的最根本因

  • 可以使用HandlerThread来模拟『单线程+队列』结构,HandlerThread就相当于是一个SingleThreadExecutor结构,即单线程池,在App启动的时候,如果有很多初始化工作不需要在UI线程完成,那么可以将这些任务发送至HandlerThread,然后顺序完成,加快应用的启动速度

在前面分析Picasso的时候,我们就看到分发器Dispatcher里面有DispatcherThread来完成任务的分发,这样对任务的处理就转换到了另外一个线程,从而不会阻塞UI线程。

HandlerThread与IntentService有什么关系?

简单一句话:IntentService的核心功能是由HandlerThread实现的。

IntentService的特点就是:任务完成后自动停止,而且不需要手动开启新的线程,默认是在工作线程完成。

如果要想知道IntentService是如何完成这个功能的,我们还是需要去翻看源码,不过IntentService也很简单,只有160行左右。

在查看源码之前,简单回顾一下IntentService的用法。

public class DownloadServices extends IntentService {

    @Override
    protected void onHandleIntent(Intent intent) {

    }

}

IntentService和普通的Service使用方法完全一样,使用ContextWrapper.startService()即可启动IntentService,因为IntentService是抽象类,因此需要直接继承,在onHandlerIntent()中会可以接收到Intent信息,需要注意的是,onHandlerIntent()是运行在工作线程的。

下面我们从源码的角度来学习IntentService的实现原理。

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;

    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);
        }
    }

    @Override
    public void onCreate() {
        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

    protected abstract void onHandleIntent(Intent intent);

}

因为IntentService继承自Service,因此Service的特性在这里也是完全通用的,这主要表现在Service的生命周期上。

当Service启动时,会先调用onCreate()完成初始化操作,在这里则是完成了HandlerThread和Handler的初始化及绑定操作,之后会调用onStartCommand(),间接在onStart()中使用mServiceHandler来发送Message,在```Handler.handleMessage()中会调用onHandleIntent()完成任务的执行。

由于内部实现使用的HandlerThread,因此HandlerThread的特性在这里仍然适用,具体来说就是指任务是以单线程串行的方式处理的。

在源码中我们可以发现,在onHandleIntent()执行之后,就会调用stopSelf(msg.arg1)来停止Service,这也是为什么IntentService不需要手动stop的原因。

还有一个问题值得我们关注,那就是如果在onHandleIntent()执行过程中,又发起了一次请求的话,IntentService是如何处理的呢?下面是这种情况的模拟,为了模拟耗时情况,在onHandleIntent()中手动延迟了3s。

@Override
    protected void onHandleIntent(Intent intent) {
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Log.d(TAG, "onHandleIntent");
    }

下面是测试结果:

D/IntentService: constructor
D/IntentService: onCreate
D/IntentService: onStartCommand
D/IntentService: onStart
D/IntentService: onStartCommand
D/IntentService: onStart
D/IntentService: onStartCommand
D/IntentService: onStart
D/IntentService: onHandleIntent
D/IntentService: onHandleIntent
D/IntentService: onHandleIntent
D/IntentService: onDestroy

因此我们可以得出结论:当onHandleIntent()未结束情况下再次发起请求时,会调用onStartComman()将任务缓存在消息队列,等待所有的任务执行完毕后,才会stop()结束IntentService。

至此我们对HandlerThread和IntentService的实现原理及用法应该有一个比较全面的认识了。

Last updated

Was this helpful?