从HandlerThread 的使用来分析HandlerThread的源码

Posted yian_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从HandlerThread 的使用来分析HandlerThread的源码相关的知识,希望对你有一定的参考价值。

转载请注明出处:
http://blog.csdn.net/yianemail/article/details/51839509

一:前言

再分析HandlerThread 的使用之前,我们先来简要介绍一下在android中线程的几种表现形式。
线程在android 中是很重要的概念,由于android的uiThread特性,我们常常要利用子线程进行耗时操作。uiThread进行界面的更新处理。在android 中,出了最为常见的Thread之外,还有AsyncTask,IntentService 以及要介绍的HandlerThread。

上述几种虽然都是android 中概念意义上的线程,但是它们具有不同的特性以及不同的使用场景。

  • AsyncTask 我们在前文已经介绍,底层封装了线程池以及利用Handler更新ui
  • IntentService内部则使用了HandlerThread
  • HandlerThread 则是Thread以及looper的封装

二:HandlerThread实例

为了表现HandlerThread 与传统的使用new thread () 的使用区别,我们分别写两个demo来加以区分。

1,通过使用new thread () 形式更新ui

看下activity代码

public class NewThreadUiActivity extends AppCompatActivity 
    private static final int MESSAGE_UI_HANDLER = 0X11;
    private static final int MESSAGE_THREAD_HANDLER = 0X12;
    private Looper threadLooper;
    private TextView textView;
    /**
     * 此handler 是UI线程的Handler
     */
    Handler uiHandler = new Handler(Looper.getMainLooper()) 
        @Override
        public void handleMessage(Message msg) 
            super.handleMessage(msg);
            switch (msg.what) 
                case MESSAGE_UI_HANDLER:
                    textView.setText("执行更新");
                    break;
            
        
    ;


    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.messgae_tv);
        /**
         * 子线程模拟耗时任务
         */
        new ThreadLooper().start();
    

    class ThreadLooper extends Thread 
        @Override
        public void run() 
            super.run();
            Looper.prepare();
            threadLooper = Looper.myLooper();
            /**
             * 子线程的Handler
             */
            Handler threadHandler = new Handler(threadLooper) 
                @Override
                public void handleMessage(Message message) 
                    super.handleMessage(message);

                    switch (message.what) 

                        case MESSAGE_THREAD_HANDLER:
                            uiHandler.sendEmptyMessageDelayed(MESSAGE_UI_HANDLER, 1000);
                            break;
                    
                
            ;

            threadHandler.sendEmptyMessageDelayed(MESSAGE_THREAD_HANDLER, 1000);

            Looper.loop();
        
    


主界面很简单,就只有一个textview,我们在onCreat()中通过执行匿名线程 。执行逻辑可能有点绕,我们看到在程序中我们实例化了uiHandler 以及threadHandler 两个handler ,其中uiHandler 用来更新界面,threadHandler 用来作为一个过渡,往uiHandler发送messgae 用来提醒uiHandler 更新界面。
你可能要问了,

“wtf ?! , 明明一个handler 就可以,你为毛弄两个?“

咳咳,这位大哥,你忘了我们本文要介绍的主题了么,HandlerThread是封装了thread 以及looper ,(注意该looper 是子线程的looper)。既然有looper 我们自然开启looper.loop() ;这样才能为后来的HandlerThread 的使用做出来更加鲜明的对比。
看下执行结果,

2,通过使用Handlerthread 形式更新ui
public class NewThreadUiActivity extends AppCompatActivity 
    private static final int MESSAGE_UI_HANDLER = 0X11;
    private static final int MESSAGE_THREAD_HANDLER = 0X12;
    private Looper threadLooper;
    private TextView textView;
    /**
     * 此handler 是UI线程的Handler
     */
    Handler uiHandler = new Handler(Looper.getMainLooper()) 
        @Override
        public void handleMessage(Message msg) 
            super.handleMessage(msg);
            switch (msg.what) 
                case MESSAGE_UI_HANDLER:
                    textView.setText("执行更新");
                    break;
            
        
    ;


    @Override
    protected void onDestroy() 
        super.onDestroy();
        //别忘了在onDestroy 退出

        handlerThread.quit();
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = (TextView) findViewById(R.id.messgae_tv);

        HandlerThread handlerThread=new HandlerThread("handlerthread");
        handlerThread.start();

        Handler threadHandler=new Handler(handlerThread.getLooper());
        uiHandler.sendEmptyMessageDelayed(MESSAGE_UI_HANDLER, 1000);

    



可以看到,采用HandlerThread 的方式为我们省去了new Thread() 以及looper.prepare()等一些列方法。获得了跟new Thread()的方式相同的效果。

三:HandlerThread源码分析

首先看HandlerThread 的实现方式

HandlerThread handlerThread = new HandlerThread("handlerthread");

 handlerThread.start();

看下构造函数

/**
 * 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.
 */
...

    public HandlerThread(String name) 
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    

其实看下它的注释就能明白大概意思,“开启一个带有looper的新的线程….请注意一定要调用start() 方法“

在构造函数中,设置了一下他的默认优先级

通过源码我们可知,HandlerThread 是Thread的子类,
再来分析一下start() 方法,(也就是run)

  @Override
    public void run() 
     //获得当前线程的id
        mTid = Process.myTid();
         //实例化message QUEUE等,
        Looper.prepare();
        //持有锁机制来获得当前线程的Looper对象
        synchronized (this) 
            mLooper = Looper.myLooper();
            notifyAll();
        
        Process.setThreadPriority(mPriority);
        //该方法实现体是空的,子类可以实现该方法,作用就是在线程循环之前做一些准备工作,
        onLooperPrepared();
         //启动loop 循环
        Looper.loop();
        mTid = -1;
    

以上代码中的注释已经写得很清楚了,以上run方法主要作用就是调用了Looper.prepare和Looper.loop构建了一个循环线程。

其实本质还是handler 的一套机制。

四:总结:

1.HandlerThread适用于构建循环线程。

2.在创建Handler作为HandlerThread线程消息执行者的时候必须调用start方法之后,因为创建Handler需要的Looper参数是从HandlerThread类中获得,而Looper对象的赋值又是在HandlerThread的run方法中创建。

源码下载:https://github.com/outparadox/HandlerThread

以上是关于从HandlerThread 的使用来分析HandlerThread的源码的主要内容,如果未能解决你的问题,请参考以下文章

HandlerThread的简单分析

Android IntentService源码理解 及 HandlerThread构建消息循环机制分析

HandlerThread使用及源码分析

HandlerThread原理分析

HandlerThread 源码分析

Android源码面试宝典之JobScheduler从使用到原理分析JobScheduler的使用