Android中HandlerThread源码解析

Android中HandlerThread源码解析

一、HanlderThread介绍

HandlerThread这个类的本质就是一个Thread,它继承自Thread类, 而且是自带Handler的线程。我们都知道在Android主线程中会自启动一个Looper去不断循环取消息、处理消息,ActivityThread中main方法中进行Looper的消息循环。而在HandlerThread内部也维护一套Looper消息循环. 这样就可以直接通过Handler向该子线程发消息,这样该Handler会把发送的消息插入到当前子线程Looper中的MessageQueue消息队列中,然后该线程就会通过loop方法,循环处理消息。注意: 这里处理消息是在子线程执行,也就意味着需要子线程执行的耗时任务就交给它来完成,以及HandlerThread相比于Thread一次创建线程,就可以不断的处理消息,减少了频繁创建线程带来的资源消耗。但是,在处理多个耗时任务时它是串行的,更多的时候它更像一个后台线程。比如BlockCanary框架中对CPU和堆栈日志的采样就是开启两个HandlerThread后台线程,进行日志采样。

二、HandlerThread的基本使用

1、创建HandlerThread, 并启动这个Thread

 mCheckMsgThread = new HandlerThread("check-message-coming");
 mCheckMsgThread.start();

2、创建HandlerThread的Handler, 注意这个Handler中的handleMessage是子线程环境

 mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper())
        {
            @Override
            public void handleMessage(Message msg)
            {
                checkForUpdate();
                if (isUpdateInfo) {                               mCheckMsgHandler.sendEmptyMessageDelayed(MSG_UPDATE_INFO, 1000);
                }
            }
        };

3、一个简单的例子-模拟服务器轮询请求-定时刷新

class MainActivity : AppCompatActivity() {
    private val mUiHandler: Handler by lazy {
        Handler(Looper.getMainLooper())
    }
    private val mHandlerThread: HandlerThread by lazy {
        HandlerThread("#check-message-coming")
    }
    private lateinit var mThreadHandler: Handler
    private var mIsUpdate: Boolean = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initBackThread()
    }

    private fun initBackThread() {
        mHandlerThread.start()
        mThreadHandler = Handler(mHandlerThread.looper) {
            Log.d("MainActivity", "current thread is ${Thread.currentThread().name}")

            Thread.sleep(1000)
            //模拟向服务器轮询请求数据,然后通过mUiHandler向主线程发送消息
            mUiHandler.post {
                //从当前线程,向主线程发送消息,刷新UI
                data_tv.text = "当前热度: ${(Math.random() * 3000 + 1000).toInt()}"
            }

            if (mIsUpdate) {
                //发送消息给mHandlerThread线程,相当于当前HandlerThread不断给自己发消息
                mThreadHandler.sendEmptyMessageDelayed(MSG_UPDATE, 1000)
            }

            return@Handler false
        }
    }

    override fun onResume() {
        super.onResume()
        mIsUpdate = true
        //发送消息给mHandlerThread线程
        mThreadHandler.sendEmptyMessage(MSG_UPDATE)
    }

    override fun onPause() {
        super.onPause()
        mIsUpdate = false
        //onPause停止更新
        mThreadHandler.removeMessages(MSG_UPDATE)
    }

    override fun onDestroy() {
        super.onDestroy()
        //注意页面销毁后,记得需要把当前线程退出,因为HandlerThread是不会自己停下来的
        mHandlerThread.quit()
    }

    companion object {
        private const val MSG_UPDATE = 0x1234
    }
}

可以看到我们在onCreate中,去创建和启动了HandlerThread,并且关联了一个mCheckMsgHandler。然后我们分别在onResumeonPause中去开启和暂停我们的查询,最后在onDestory中去释放资源。

三、HandlerThread使用场景

  • 需要子线程处理任务

  • 需要处理多个任务

  • 需要处理实时耗时的任务,比如定时轮询,页面实时自动刷新

四、HandlerThread的源码解析

1、创建的HandlerThread对象,然后启动
   private val mHandlerThread: HandlerThread by lazy {
        HandlerThread("#check-message-coming")
   }

   private fun initBackThread() {
        mHandlerThread.start()//因为HandlerThread本质还是一个Thread,调用start方法后,会映射启动本机OS的线程,最后也会回调触发执行run方法
   }     
2、在HandlerThread的内部主要核心run方法
    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();//调用Looper的prepare方法创建一个与当前线程绑定的Looper对象,然后把它保存在Looper的ThreadLocal中,创建Looper对象的同时还会创建一个消息队列MessageQueue
        synchronized (this) {
            mLooper = Looper.myLooper();//然后通过myLooper方法,从Looper的ThreadLocal中取出当前线程绑定的Looper对象
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();//然后启动Looper消息循环系统,该线程Looper创建的Handler发送消息,就会把消息插入到当前线程的Looper的消息队列中,然后loop方法就不断从消息队列中取出消息
        mTid = -1;
    }

//getLooper,获取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();//如果当前线程已经启动了,会一直等待直到Looper对象被创建,以便于返回Looper对象
                } catch (InterruptedException e) {
                }
            }
        }
        return mLooper;
    }
3、HandlerThread的quit方法,退出当前的线程,实际上就是终止和退出Looper消息循环。
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();//调用Looper的quit退出消息循环,实际就是调用了MessageQueue的quit方法
            return true;
        }
        return false;
    }

   转载规则


《Android中HandlerThread源码解析》 mikyou 采用 知识共享署名 4.0 国际许可协议 进行许可。
 上一篇
Android中AsyncTask源码解析 Android中AsyncTask源码解析
Android中AsyncTask源码解析一、AsyncTask描述 AsyncTask是一种轻量级的异步任务处理类,它可以在线程池中执行后台任务,并且能把执行进度以及最终在线程池中执行异步任务结果传递主线程进行UI刷新,也就是我们常说的线
2019-12-29
下一篇 
Android中IntentService源码解析 Android中IntentService源码解析
Android中IntentService源码解析一、IntentService的介绍 IntentService是一种特殊的Service,它继承了Service并且它是一个抽象类,所以一般情况下我们会它的子类来实现,它一般用于后台耗时的
2019-12-29