美文网首页
ThreadLocal、HandlerThread以及Inten

ThreadLocal、HandlerThread以及Inten

作者: 不讲道理的魏同学 | 来源:发表于2019-05-12 15:55 被阅读0次

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.
     *
     * <p>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.
     *
     * <p>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以及Inten

      本文链接:https://www.haomeiwen.com/subject/jthcaqtx.html