Android HandlerThread使用介绍以及源码解析
摘要: 版权声明:本文出自汪磊的博客,转载请务必注明出处。
一、HandlerThread的介绍及使用举例
HandlerThread是什么鬼?其本质就是一个线程,但是HandlerThread在启动的时候会帮我们准备好一个Looper,并供外界使用,说白了就是使我们在子线程中更方便的使用Handler,比如没有HandlerThread我们要在子线程使用Handler,写法如下:
1 private Handler mHandler;
2
3 @Override
4 public void run() {
5 super.run();
6
7 Looper.prepare();
8
9 mHandler = new Handler(){
10
11 @Override
12 public void handleMessage(Message msg) {
13
14 }
15 };
16
17 Looper.loop();
18 }
有了HandlerThread就不用我们自己管理Looper了,至于为什么分析源码的时候就明白了。
HandlerThread使用简单介绍:
首先我们要初始化HandlerThread然后调用其start方法,也就是开启线程:
1 mHandlerThread = new HandlerThread("mHandlerThread");//这里的mHandlerThread其实就是线程的名字
2 mHandlerThread.start();
接下来初始化一个Handler并且将mHandlerThread中的Looper作为构造函数参数传递给Handler:
1 mHandler = new Handler(mHandlerThread.getLooper())
这样就保证了Hnadler运行在子线程。并且需要在适合的时机调用HandlerThread的quit方法或quitSafely方法,如Activity销毁的时候:
1 @Override
2 protected void onDestroy() {
3 //
4 super.onDestroy();
5 //释放资源
6 mHandlerThread.quit();
7 }
quit()与quitSafely()方法比较(这里只说一些结论,源码可以自己查看):
相同点:
调用之后MessageQueue消息队列均不在接受新的消息加入队列。
不同点:
quit方法把MessageQueue消息池中所有的消息全部清空。quitSafely方法只会清空MessageQueue消息池中所有的延迟消息(延迟消息是指通过sendMessageDelayed或postDelayed等方法发送的消息),非延迟消息则不清除继续派发出去让Handler去处理。
接下来我们完整看一下HandlerThread例子源码:
1 public class MainActivity extends Activity {
2
3 private HandlerThread mHandlerThread;
4 private Handler mHandler;
5 private boolean flag;
6 //
7
8 @Override
9 protected void onCreate(Bundle savedInstanceState) {
10 super.onCreate(savedInstanceState);
11 setContentView(R.layout.activity_main);
12
13 mHandlerThread = new HandlerThread("mHandlerThread");
14 mHandlerThread.start();
15
16 mHandler = new Handler(mHandlerThread.getLooper()) {
17
18 @Override
19 public void handleMessage(Message msg) {
20 //
21 try {
22 Thread.sleep(2000);
23 } catch (InterruptedException e) {
24 e.printStackTrace();
25 }
26
27 if(flag){
28 Log.i("HandlerThread", "更新:"+new Random().nextInt(1000));
29 }
30 mHandler.sendEmptyMessage(1);
31 }
32 };
33
34 }
35
36 @Override
37 protected void onResume() {
38 //
39 super.onResume();
40 flag = true;
41 mHandler.sendEmptyMessage(1);
42 }
43
44 @Override
45 protected void onPause() {
46 //
47 super.onPause();
48 flag = false;
49 }
50
51 @Override
52 protected void onDestroy() {
53 //
54 super.onDestroy();
55 //释放资源
56 mHandlerThread.quit();
57 }
58 }
运行程序就会在控制台看到每隔两秒有Log打出。至于HandlerThrea的使用就到此为止了,看懂上面小例子就差不多了。
二、HandlerThread的源码分析
HandlerThread源码非常简短,出去注释不到100行,这里就直接全部贴出来了:
1 public class HandlerThread extends Thread {
2 int mPriority;
3 int mTid = -1;
4 Looper mLooper;
5
6 public HandlerThread(String name) {
7 super(name);
8 mPriority = Process.THREAD_PRIORITY_DEFAULT;
9 }
10
11 /**
12 * Constructs a HandlerThread.
13 * @param name
14 * @param priority The priority to run the thread at. The value supplied must be from
15 * {@link android.os.Process} and not from java.lang.Thread.
16 */
17 public HandlerThread(String name, int priority) {
18 super(name);
19 mPriority = priority;
20 }
21
22 /**
23 * Call back method that can be explicitly overridden if needed to execute some
24 * setup before Looper loops.
25 */
26 protected void onLooperPrepared() {
27 }
28
29 @Override
30 public void run() {
31 mTid = Process.myTid();
32 Looper.prepare();
33 synchronized (this) {
34 mLooper = Looper.myLooper();
35 notifyAll();
36 }
37 Process.setThreadPriority(mPriority);
38 onLooperPrepared();
39 Looper.loop();
40 mTid = -1;
41 }
42
43 /**
44 * This method returns the Looper associated with this thread. If this thread not been started
45 * or for any reason is isAlive() returns false, this method will return null. If this thread
46 * has been started, this method will block until the looper has been initialized.
47 * @return The looper.
48 */
49 public Looper getLooper() {
50 if (!isAlive()) {
51 return null;
52 }
53
54 // If the thread has been started, wait until the looper has been created.
55 synchronized (this) {
56 while (isAlive() && mLooper == null) {
57 try {
58 wait();
59 } catch (InterruptedException e) {
60 }
61 }
62 }
63 return mLooper;
64 }
65
66
67 public boolean quit() {
68 Looper looper = getLooper();
69 if (looper != null) {
70 looper.quit();
71 return true;
72 }
73 return false;
74 }
75
76
77 public boolean quitSafely() {
78 Looper looper = getLooper();
79 if (looper != null) {
80 looper.quitSafely();
81 return true;
82 }
83 return false;
84 }
85
86 /**
87 * Returns the identifier of this thread. See Process.myTid().
88 */
89 public int getThreadId() {
90 return mTid;
91 }
92 }
看第一行就知道了其本质就是一个线程。
6-9行以及17-20行构造函数,也很简单,就是初始化的时候我们可以定义线程名字,还可以传入线程优先级。
初始化完成,紧接着调用start()开发线程就会执行run方法逻辑。
30-41行代码,最重要的就是调用Looper.prepare()以及Looper.loop()方法为我们在子线程准备好一个Looper。并且用变量mLooper记录,调用getLooper()方法的时候返回。
但是,细心的你肯定发现run()方法中有个notifyAll(),getLooper()中有个wait()为什么要加这些鸟玩意?
大家发现没在HandlerThread 例子中Handler的创建是在主线程完成的,创建的时候需要调用HandlerThread的getLooper()获取mLooper作为参数传递给Handler的构造函数,而Looper的创建是在子线程中创建的,这里就有线程同步问题了,比如我们调用getLooper()的时候HandlerThread中run()方法还没执行完,mLooper变量还未赋值,此时就执行了wait()等待逻辑,一直等到run()方法中mLooper被赋值,之后立即执行notifyAll(),然后getLooper()就可以正确返回mLooper了。
明白了吧,不明的话这里需要花些时间好好理解下,好了源码主要部分就分析完了,看到这里相信你对HandlerThread有了一定的了解了。
HandlerThread 还是比较简单理解的,好了,本篇到此为止,希望对你有帮助。