ThreadLocal、HandlerThread以及IntentService三者关系全面解析

Android SDK里面很多类名都起的让人傻傻分不清楚,本篇文章就是从IntentService这个组件的生命周期出发,深度剖析ThreadLocalHandlerThread以及IntentService之间错综复杂的关系。

首先了解概念

ThreadLocal:线程的本地变量。该变量不与其他线程共享,只能在本线程内操作。

HandlerThread:一种经过包装的Thread。随着该thread启动,其内部的Looper会自动开始循环。

IntentService:一种经过包装的Service。该Service内部会自动开启一个线程用来执行任务,并在任务结束后自动结束。

敲黑板!记住结论:

  1. HandlerThread本质上仍是一个Thread。
  2. IntentService本质上仍是一个Service。

IntentService的生命周期

既然IntentService也是个Service,那么就从它的onCreate方法看起。

IntentService的onCreate方法.png

关注三个点:

  1. 实例化了一个HandlerThread,并启动该线程。
  2. 获取该HandlerThread中自带的Looper对象。
  3. 将获取到的Looper对象作为参数用来实例化ServiceHandler。
HandlerThread部分源码.png

首先,通过阅读HandlerThread的源码,可以发现HandlerThread在run方法中会帮我们创建好一个Looper并让该Looper执行loop方法。在深入理解Handler、Looper与MessageQueue之间的关系一文中,我们详细的描述了Handler、Looper以及MesageQueue三者之间的关系。Looper循环是Handler能在线程中运行的前提条件。
所以我们可以理解为,IntentService的onCreate方法中所用到的HandlerThread,相当于是为IntentService快速的构建并启动了一个带有Looper的工作线程

Looper部分源码.png
其次,Looper在其prepare方法中会通过ThreadLocal将自身与当前线程进行绑定。同样的,在通过Looper.myLooper获取当前线程的Looper对象时,也是通过ThreadLocal进行获取。

最后一点,就是ServiceHandler。

ServiceHandler源码.png

ServiceHandler的构造函数没什么好讲的,和普通Handler一样。重点在于其handleMessage方法。
handlerMessage方法用来处理由Looper循环MessageQueue所得到的Message。此处的代码逻辑为,当有Message发送来,则会调用onHandleIntent方法进行处理,而这个onHandleIntent方法则正是我们使用IntentService时必须要实现的抽象方法。当onHandleIntent方法执行完,便会调用Service的stopSelf方法终止该IntentService,以此达到任务执行完自动结束的效果。

下面放上IntentService的完整代码:

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

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

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }

    /**
     * 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 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); } @Override public void onStart(@Nullable Intent intent, int startId) { Message msg = mServiceHandler.obtainMessage(); msg.arg1 = startId; msg.obj = intent; mServiceHandler.sendMessage(msg); } /** * 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; } @Override public void onDestroy() { mServiceLooper.quit(); } /** * Unless you provide binding for your service, you don't need to implement this * method, because the default implementation returns null. * @see android.app.Service#onBind */ @Override @Nullable public IBinder onBind(Intent intent) { return null; } /** * 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的执行过程:
首先IntentService执行onCreate方法,该方法中会创建一个HandlerThread线程并实例化一个内部类ServiceHandler。
随后,onStartCommand方法会调用onStart方法,在onStart方法内部,会构造一个Message,然后用ServiceHandler来发送该Message。
再之后,ServiceHandler的handleMessage方法会对发来的Mesage进行处理,具体的处理逻辑则是交给抽象方法onHandleIntent来完成,而这个方法正是使用者使用IntentService必须要实现的方法,使用者应该将该Service要执行的任务写在该抽象方法的实现中。
在onHandleIntent方法完成后,便会执行Service的stopSelf(int id)方法,来结束该IntentService。
最后,在IntentService的onDestroy方法里,通过执行mServiceLooper的quit()方法,终止掉该Looper循环,也顺带结束了该IntentService对应的工作线程。

通过整体流程分析,我们可以发现,IntentService为我们封装好了工作线程的初始化、启动以及结束相关的代码,使得开发者能专注于业务逻辑的编写,减少了忘记结束Service所带来的内存泄漏的威胁。

你可能感兴趣的:(ThreadLocal、HandlerThread以及IntentService三者关系全面解析)