HandlerThread之源码完全解析
此文是我还在学校[2016-06-28]那段时间写的文章, 当时记录在公众号中,由于长期没有继续维护,随搬迁至此博客.
前言
在正文开始之前如果你对Handler还存有疑惑,建议先看看我的另一篇文章从源码角度分析Handler、Looper、MessageQueue三角关系再继续看下去,如果已经有了一定的了解了,接下来这篇文章读起来将会很轻松哒~
在开始HandlerThread源码之前我们先写一个与线程相关的Handler
代码部分
- time.xml
|
|
布局很简单,一个TextView去展示界面
- TimeActivity.java
|
|
代码我们定义一个内部类MyThread,紧接着通过looper = Looper.myLooper()拿到储存在sThreadLocal的Looper实例,如果这里听不懂的话建议回头看看从源码角度分析Handler、Looper、MessageQueue三角关系这篇文章,重写handleMessage最后调用Looper的loop方法,从MessageQueue中去取消息。定义一个checkForUpdate方法模拟从服务器解析数据,通过post方法创建一个线程,最后在run方法里面更新UI,模拟时钟。
咳咳,这里我得先打住,有谁看到这段代码以为是创建了一个线程请举个手(yo~put ur hands up🙌)!!!
|
|
我告诉你其实什么线程都没有被创建,请看源码
|
|
是不是觉得这几行代码很亲切呢,继续看下去
|
|
可以看到,getPostMessage将Runnable的对象r复制给了Message的callback。回头看看sendMessageDelayed是不是很熟悉呢?没错,跟handler的sendMessageDelayed一模一样。我们再看看下面这段代码
|
|
我们拿到Looper对象后通过Looper.loop()方法在MessageQueue中不断轮回拿取数据,然后回调msg.target.dispatch(…),这里通过判断msg.callback是否为空,如果不为空就执行回调方法handleCallback(msg),而在前面我们已经给callback赋值了,就是Runnable
|
|
紧接着调用run方法在里面更新我们的UI代码,代码其实就这些,一点也不复杂是不是?
插叙就这么多,接着我们打开模拟器Genymotion运行下我们的代码
我们发现程序奔溃了,正常思维我们看看日志报什么错误
日志报了个RuntimeException空指针错误,为什么呢?我们再看看这行代码myThread.mhandler = new Handler(myThread.looper),我们传入新建的thread的looper,这里涉及到了线程并发的问题因为两个线程交叉运行当编译器运行到这段代码时但此时的looper却没被创建就会报出空指正的问题。那我们改如何避免这个问题呢?很幸运google已经帮我事先考虑到了,所以才有了HandlerThread,下面修改下代码,仅两处
- 1、定义一个HandlerThread和Handler
|
|
这里我们不再需要MyThread这个类了,在initBackThread方法内实例化HandlerThread
|
|
HandleThread需要传入有个线程名字,这里随意
|
|
我们重新跑一次程序(掉帧得好厉害,但效果还是看得出来啦~)