美文网首页
Android之HandlerThread的探索

Android之HandlerThread的探索

作者: 放码过来吧 | 来源:发表于2018-03-20 18:25 被阅读104次

    之前分析了IntentHandler的内部实现原理,里面用的就是HandlerThread来进行异步处理事件(想看可以点击intentHandler),然而当时并没有解释HandlerThread跟普通的Thread的区别,现在来分析下它的内部实现相关。

    问题提出
    1、HandlerThread是什么?
    2、HandlerThread跟普通的Thread有何区别?
    3、HandlerThread内部实现分析。
    4、HandlerThread使用场景。


    1.jpg

    分析与解决问题
    我们先看看源码里面对HandlerThread的解释:

    /**
     * Handy class for starting a new thread that has a looper. The looper can then be 
     * used to create handler classes. Note that start() must still be called.
     */
    

    大概讲的意思就是:HandlerThread是一个拥有looper的子线程,这个looper可以用来创建handler类。注意,创建的HandlerThread对象的start()方法一定要执行。
    很好,现在我们知道了,HandlerThread是一个继承与Thread的子线程,区别就在于,HandlerThread提供了创建handler对象的looper。
    接下来,看看它的内部实现:

        public HandlerThread(String name) {
            super(name);
            mPriority = Process.THREAD_PRIORITY_DEFAULT;
        }
    
        /**
         * Constructs a HandlerThread.
         * @param name
         * @param priority The priority to run the thread at. The value supplied must be from 
         * {@link android.os.Process} and not from java.lang.Thread.
         */
        public HandlerThread(String name, int priority) {
            super(name);
            mPriority = priority;
        }
    

    构造函数里面的mPriority,优先级相关的,可以根据自己的需求去设置。

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

    在Looper.prepare()里面,其实就是创建looper对象,并赋值给mLooper.onLooperPrepared()里面是空方法,我们可以重写,做一些初始化的操作,然后调用Looper.loop()方法启动了了loop。在这里,我们有一些疑惑,synchronized?notifyAll()?稍后我们在来分析,我们先看看prepare()内部实现:

     public static void prepare() {
            prepare(true);
        }
    
        /**
         * sThreadLocal.get() will return null unless you've called prepare().
         */
        static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
        private static void prepare(boolean quitAllowed) {
            if (sThreadLocal.get() != null) {
                throw new RuntimeException("Only one Looper may be created per thread");
            }
            sThreadLocal.set(new Looper(quitAllowed));
        }
    

    把创建的Looper对象放到的sThreadLocal。放进去总要取出来吧,我们来看看Looper.myLooper()内部的实现:

    
        /**
         * Return the Looper object associated with the current thread.  Returns
         * null if the calling thread is not associated with a Looper.
         */
        public static @Nullable Looper myLooper() {
            return sThreadLocal.get();
        }
    

    贼简单,就是把之前存进去的looper对象取出来并返回。现在looper创建了,总要用上吧,这个时候就应该想到handler了,我们来看看提供的获取handler的方法getThreadHandler():

        /**
         * @return a shared {@link Handler} associated with this thread
         * @hide
         */
        @NonNull
        public Handler getThreadHandler() {
            if (mHandler == null) {
                mHandler = new Handler(getLooper());
            }
            return mHandler;
        }
    

    这个方法可以获取一个有当前子线程looper的handler对象,我们来看看getLooper(),可以看出是获取looper对象的方法:

       /**
         * This method returns the Looper associated with this thread. If this thread not been started
         * or for any reason isAlive() returns false, this method will return null. If this thread
         * has been started, this method will block until the looper has been initialized.  
         * @return The looper.
         */
        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;
        }
    

    这里面,isAlive()方法的意思是线程不正常运行就返回null,接着,如果looper还没创建好就wait()等待,创建后notifyAll。在这里,我们来分析下为什么会用到wait,notifyAll等相关:handler对象的创建方法(getThreadHandler())调用是在UI线程里面,but,Looper在一个线程中执行创建的,为了确保looper创建完成之后在创建handler对象,所以需要wait(),notify()来处理线程同步问题。

    总结:HandlerThread其实就是一个封装了handler的Thread的子类,做好前奏工作后,让我们在线程中直接使用handler来处理一个或者多个异步操作。使用场景,就是适合那些多个并按顺序执行的耗时任务的相关需求,可以跟intentService配合使用。(intentService内部异步处理用的就是HandlerThread)

    相关文章

      网友评论

          本文标题:Android之HandlerThread的探索

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