美文网首页
Android HandlerThread详解(源码分析)

Android HandlerThread详解(源码分析)

作者: Jere_Chen | 来源:发表于2020-01-30 20:49 被阅读0次

    目录:

    目录

    1. 前言

    本篇文章是对 Android HandlerThread 类的学习,通过简单的例子,及分析源码来深入学习。同时例子将以 Java & Kotlin 两种代码形式展示。

    1.1 定义

    HandlerThread: 一个拥有 Looper 对象的线程。

    继承于 Thread 类,并拥有一个 Looper 对象,可以利用该 Looper 对象来创建 Handler 对象,就像正常的线程一样,通过调用 start() 方法来开启线程。

    1.2 使用场景

    适用于子线程多任务的工作场景。如:多个网络请求,多个I/O操作

    2. 使用方法

    其使用方法很简单:

    1. 在主线程中新建一个 HandlerThread 对象,然后调用 start() 方法启动该线程。
    2. 创建一个主线程Handler 对象,关联APP主Looper对象,用于子线程与主线程之间的沟通。
    3. 创建一个工作线程Handler 对象,关联 HandlerThread 的 Looper 对象。
    4. 发送消息给工作线程,工作线程Handler 接收消息,并处理消息,然后调用主线程。Handler,发送信息给主线程,通知主线程做UI工作。
    5. 当对应的 Activity 销毁时,退出 HandlerThread,终止消息循环。

    比如:我们用两个 ProgressBar 来模拟在子线程中进行下载任务,点击按钮开始下载,ProgressBar 的进度代表着下载进度。
    如下所示:


    HandlerThread子线程执行多任务.gif

    2.1 Java版本

    具体代码如下:

    public class HandlerThreadActivity extends AppCompatActivity {
        private final int SET_PROGRESS_BAR_1 = 1;
        private final int SET_PROGRESS_BAR_2 = 2;
        private HandlerThread myHandlerThread;
        private Handler mWorkHandler, mMainHandler;
        private ProgressBar progressBar1, progressBar2;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_handler_thread);
    
            TextView titleTv = findViewById(R.id.title_tv);
            titleTv.setText("HandlerThread");
    
            progressBar1 = findViewById(R.id.progress_bar_1);
            progressBar2 = findViewById(R.id.progress_bar_2);
            Button startBtn1 = findViewById(R.id.start_progress_bar_1_btn);
            Button startBtn2 = findViewById(R.id.start_progress_bar_2_btn);
    
            //创建HandlerThread对象
            myHandlerThread = new HandlerThread("myHandlerThread");
            //启动线程
            myHandlerThread.start();
    
            //创建主线程Handler,关联APP的主Looper对象
            mMainHandler = new Handler(getMainLooper());
    
            //创建工作线程Handler,关联HandlerThread的Looper对象,所以它无法与主线程通讯
            mWorkHandler = new Handler(myHandlerThread.getLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
    
                    switch (msg.what) {
                        case SET_PROGRESS_BAR_1:
                            //设置Progress Bar 1
                            for (int i = 1; i <= 4; i++) {
                                try {
                                    //模拟耗时工作
                                    Thread.sleep(1000);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
    
                                final int progressSchedule = I;
                                //在工作线程中,通过主线程Handler, 传递信息给主线程,通知主线程处理UI工作。
                                mMainHandler.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        progressBar1.setProgress(progressSchedule);
                                    }
                                });
                            }
                            break;
                        case SET_PROGRESS_BAR_2:
                            //设置Progress Bar 2
                            for (int i = 1; i <= 4; i++) {
                                try {
                                    //模拟耗时工作
                                    Thread.sleep(1300);
                                } catch (InterruptedException e) {
                                    e.printStackTrace();
                                }
    
                                final int progressSchedule2 = I;
                                //在工作线程中,通过主线程Handler, 传递信息给主线程,通知主线程处理UI工作。
                                mMainHandler.post(new Runnable() {
                                    @Override
                                    public void run() {
                                        progressBar2.setProgress(progressSchedule2);
                                    }
                                });
                            }
                            break;
                        default:
                            break;
                    }
                }
            };
    
            startBtn1.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //通过工作线程Handler,mWorkHandler发送处理 progress bar 1 的信息给工作线程。
                    Message msg = new Message();
                    msg.what = SET_PROGRESS_BAR_1;
                    mWorkHandler.sendMessage(msg);
                }
            });
    
            startBtn2.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //通过工作线程Handler mWorkHandler发送处理 progress bar 2 的信息给工作线程。
                    Message msg = new Message();
                    msg.what = SET_PROGRESS_BAR_2;
                    mWorkHandler.sendMessage(msg);
                }
            });
    
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            myHandlerThread.quit();
        }
    }
    

    2.2 Kotlin版本

    Kotlin 版本代码如下:

    class TestHandlerThreadActivity : AppCompatActivity(), View.OnClickListener {
        var mHandlerThread: HandlerThread? = null
        var mMainHandler: Handler? = null
        var mWorkHandler: WorkHandler? = null
    
        override fun onClick(v: View?) {
            when (v?.id) {
                R.id.handlerThreadStart1Btn -> mWorkHandler?.obtainMessage(1)?.sendToTarget()
                R.id.handlerThreadStart2Btn -> mWorkHandler?.obtainMessage(2)?.sendToTarget()
            }
        }
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_test_handler_thread)
    
            mMainHandler = Handler(Looper.getMainLooper())
    
            mHandlerThread = HandlerThread("JereTest")
            mHandlerThread!!.start()
            mWorkHandler = WorkHandler(mHandlerThread!!.looper)
    
            handlerThreadStart1Btn.setOnClickListener(this)
            handlerThreadStart2Btn.setOnClickListener(this)
        }
    
        inner class WorkHandler(looper: Looper) : Handler(looper) {
    
            override fun handleMessage(msg: Message) {
                super.handleMessage(msg)
                when (msg.what) {
                    1 -> {
                        for (i in 1..5) {
                            Thread.sleep(1000)
                            mMainHandler?.post { handlerThreadProgressBar1.progress = I }
                        }
                    }
                    2 -> {
                        for (j in 1..5) {
                            Thread.sleep(1000)
                            mMainHandler?.post { handlerThreadProgressBar2.progress = j }
                        }
                    }
                }
            }
    
        }
    
        override fun onDestroy() {
            super.onDestroy()
            mHandlerThread?.quit()
        }
        
    }
    

    3. 源码分析

    按使用步骤来分析源码:

    HandlerThread使用方法

    步骤一:在主线程中新建一个 HandlerThread 对象,然后调用 start() 方法启动该线程。

    //创建 HandlerThread 对象
    myHandlerThread = new HandlerThread("myHandlerThread");
    //启动线程,执行 run() 方法
    myHandlerThread.start();
    
    //创建 HandlerThread 对象,看其构造函数
    /**
     * HandlerThread的构造函数
     * @param name,线程名字是我们传入的,用于标记改线程
     */
    public HandlerThread(String name) {
        super(name);
        //指定该线程的优先级为标准线程优先级
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    
    //启动线程
    @Override
    public void run() {
        //获得线程标识符
        mTid = Process.myTid();
        //为该线程创建一个 Looper 对象,具体见下:
        Looper.prepare();
        synchronized (this) {
            //获取通过 Looper.prepare() 方法创建的 Looper 对象。
            mLooper = Looper.myLooper();
            //唤醒那些为创建Looper对象而阻塞的线程
            notifyAll();
        }
        //设置该线程的优先级,比如设置为标准线程优先级
        Process.setThreadPriority(mPriority);
        //消息循环前做的处理,即:如果想在消息循环前做一些处理,则需要复写onLooperPreopared()方法。
        onLooperPrepared();
        //循环该Looper对象中的消息队列
        Looper.loop();
        mTid = -1;
    }
    

    步骤二:创建一个主线程Handler 对象,关联APP主Looper对象,用于子线程与主线程之间的沟通。

    //创建主线程Handler,关联APP的主Looper对象
    mMainHandler = new Handler(getMainLooper());
    

    其具体源码分析内容请看另外一篇文章Android Handler 深入学习及源码分析

    步骤三. 创建一个工作线程Handler 对象,关联 HandlerThread 的 Looper 对象。
    其具体实现方法如下:

    //创建工作线程Handler,关联HandlerThread的Looper对象,所以它无法与主线程通讯
    mWorkHandler = new Handler(myHandlerThread.getLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
                ···略···
        }
    };
    

    通过 getLooper() 方法获取 HandlerThread 的 Looper 对象,其源码如下:

    /**
     * 该方法返回该线程所关联的Looper对象。
     * 如果这个线程没有启动,或者由于任何原因isAlive()返回false,那么这个方法将返回null。
     * 如果这个线程已经启动,这个方法将阻塞,直到looper被初始化。
     * @return The looper.
     */
    public Looper getLooper() {
        //线程未激活,返回 null
        if (!isAlive()) {
            return null;
        }
        
        //如果该线程已经启动,则阻塞该方法,直到创建好Looper对象。
        synchronized (this) {
            while (isAlive() && mLooper == null) {
                try {
                    wait();
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
    

    步骤四:发送消息给工作线程,工作线程Handler 接收消息,并处理消息,然后调用主线程Handler,发送信息给主线程,通知主线程做UI工作。
    Handler 通过 sendMessage(Msg) 及 post(Runnable) 方法传递消息,本篇博客不展开具体分析,具体源代码分析见上一篇博客Android Handler 深入学习及源码分析

    步骤五:当对应的 Activity 销毁时,退出 HandlerThread,终止消息循环。
    当当前 Activity 退出销毁时,复写 onDestry() 方法,退出 HandlerThread,如:

    @Override
    protected void onDestroy() {
        super.onDestroy();
        myHandlerThread.quit();
    }
    

    通过 quit() 方法退出 HandlerThread,终止消息循环,具体源代码分析,见下:

    /**
     * 终止 Handler 关联的 looper 消息循环,不在处理消息队列中的任何消息。
     * 当 looper 被停止后再尝试请求消息入消息队列,会失败,比如:sendMessage(Message) 会返回 false。
     * 使用该方法可能不安全,因为 looper 在没有循环分发完所有消息时就被停止了。
     * 考虑使用quitsafe() 方法来代替,以确保所有未完成的工作以有序的方式完成。
     *
     * @return 如果Looper停止消息循环,返回True; 如果线程尚未开始运行,则返回false。
     */
    public boolean quit() {
        //获取 Handler 所关联的 Looper 对象。
        Looper looper = getLooper();
        //如果 Looper 不为空,停止其消息循环,返回true
        if (looper != null) {
            looper.quit();
            return true;
        }
        //如果 Looper 为空,即现场还未开始运行,返回 false。
        return false;
    }
    
    /**
     * 安全的终止 Handler 关联的 Looper 消息循环,处理消息队列中所有已到期的消息,而未到期的挂起的延迟消息将不被传递
     * 处理完消息队列中的所有消息后立即停止 Looper 消息循环
     * 当 looper 被停止后再尝试请求消息入消息队列,会失败,比如:sendMessage(Message) 会返回 false。
     * 如果线程还未开始或已经结束(getLooper 返回 null),返回false;另外,当 Looper 被要求 quit() 停止消息循环时,返回true。
     *
     * @return 如果Looper停止消息循环,返回True; 如果线程尚未开始运行,则返回false。
     */
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            //
            looper.quitSafely();
            return true;
        }
        return false;
    }
    

    至此 HandlerThread 的源码也就分析结束了。
    其实分享文章的最大目的正是等待着有人指出我的错误,如果你发现哪里有错误,请毫无保留的指出即可,虚心请教。

    另外,如果你觉得文章不错,对你有所帮助,请给我点个赞,就当鼓励,谢谢~Peace~!

    相关文章

      网友评论

          本文标题:Android HandlerThread详解(源码分析)

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