Android - Thread Handler HandlerThread Looper MessageQueue理解
Android - Thread Handler HandlerThread Looper MessageQueue理解
一、前期知识储备
(1)Handler类,上官方文档,Handler
public class Handler.A Handler allows you to send and process Message and Runnable objects associated with a thread's MessageQueue. Each Handler instance is associated with a single thread and that thread's message queue. When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
There are two main uses for a Handler: (1) to schedule messages and runnables to be executed as some point in the future; and (2) to enqueue an action to be performed on a different thread than your own.
(2)Thread类,上官方文档,Thread
public class Thread. extends Object implements Runnable.A thread is a thread of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently.
Every thread has a priority. Threads with higher priority are executed in preference to threads with lower priority. Each thread may or may not also be marked as a daemon. When code running in some thread creates a new Thread object, the new thread has its priority initially set equal to the priority of the creating thread, and is a daemon thread if and only if the creating thread is a daemon.
(3)HandlerThread类,上官方文档,HandlerThread
public class HandlerThread. extends Thread. 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.
二、三者的区别
①Handler:在android中负责发送和处理消息,通过它可以实现其他支线线程与主线程之间的消息通讯。
②Thread:Java进程中执行运算的最小单位,亦即执行处理机调度的基本单位。某一进程中一路单独运行的程序。
③HandlerThread:一个继承自Thread的类HandlerThread,Android中没有对Java中的Thread进行任何封装,而是提供了一个继承自Thread的类HandlerThread类,这个类对Java的Thread做了很多便利的封装。
自我理解:
1.Looper跟当前Object对象是绑定的,也就是说业务逻辑就在当前对象的主线程里进行。
例如:
public class MainActivity extends AppCompatActivity {
....
//创建一个与主线程关联的handler(绑定了looper)
mainHandler = new Handler();
....
}
由上可见,此是的mainHandler(绑定了Looper)对象是跟MainActivity绑定,所以Looper的业务逻辑是在MainActivity这个类的主线程下进行的。
2. 关于Runnable的理解,Runnable只是一个接口,new一个Runnable并不是说创建了一个子线程。来看下Thread定义中提到的一句话,public class Thread. extends Object implements Runnable. 线程继承自Object 并实现Runnable接口,所以就算主线程也要实现这个方法。
接着上面的代码,举例:
public class MainActivity extends AppCompatActivity {
....
//创建一个与主线程关联的handler(绑定了looper)
mainHandler = new Handler();
....
1 // 通过主线程Handler.post方法进行在主线程的UI更新操作 2 mainHandler.post(new Runnable() { 3 @Override 4 public void run () { 5 text.setText("第一次执行"); 6 } 7 });
}
其中post的作用了类似于Handler的send方法,是将Runnable的逻辑丢进Looper(MessageQueue), 消息用send, Runnable用post。
所以上面的“text.setText("第一次执行");”是在主线程中执行的,也可以通过这样的方式可以让UI操作切换到主线程下执行。
下面来看下具体完成的例子,来模拟子线程和主线程的通信,也更好的了解Handler 和 HandlerThread的区别。谷歌封装了HandlerThread类,它类似于AsyncTask类。
1 public class MainActivity extends AppCompatActivity { 2 3 Handler mainHandler,workHandler; 4 HandlerThread mHandlerThread; 5 TextView text; 6 Button button1,button2; 7 8 @Override 9 protected void onCreate(Bundle savedInstanceState) { 10 super.onCreate(savedInstanceState); 11 setContentView(R.layout.activity_main); 12 text = (TextView) findViewById(R.id.text1); 13 14 // 创建与主线程关联的Handler 15 mainHandler = new Handler(); 16 /** 17 * 步骤①:创建HandlerThread实例对象 18 * 传入参数 = 线程名字,作用 = 标记该线程 19 */ 20 mHandlerThread = new HandlerThread("handlerThread"); 21 22 /** 23 * 步骤②:启动线程 24 */ 25 mHandlerThread.start(); 26 27 /** 28 * 步骤③:创建工作线程Handler & 复写handleMessage() 29 * 作用:关联HandlerThread的Looper对象、实现消息处理操作 & 与其他线程进行通信 30 * 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行 31 */ 32 33 workHandler = new Handler(mHandlerThread.getLooper()){ 34 @Override 35 public void handleMessage(Message msg) 36 { 37 //设置了两种消息处理操作,通过msg来进行识别 38 switch(msg.what){ 39 case 1: 40 try { 41 //延时操作 42 Thread.sleep(1000); 43 } catch (InterruptedException e) { 44 e.printStackTrace(); 45 } 46 // 通过主线程Handler.post方法进行在主线程的UI更新操作 47 mainHandler.post(new Runnable() { 48 @Override 49 public void run () { 50 text.setText("第一次执行"); 51 } 52 }); 53 break; 54 case 2: 55 try { 56 Thread.sleep(3000); 57 } catch (InterruptedException e) { 58 e.printStackTrace(); 59 } 60 mainHandler.post(new Runnable() { 61 @Override 62 public void run () { 63 text.setText("第二次执行"); 64 } 65 }); 66 break; 67 default: 68 break; 69 } 70 } 71 }; 72 73 /** 74 * 步骤④:使用工作线程Handler向工作线程的消息队列发送消息 75 * 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作 76 */ 77 button1 = (Button) findViewById(R.id.button1); 78 button1.setOnClickListener(new View.OnClickListener() { 79 @Override 80 public void onClick(View v) { 81 Message msg = Message.obtain(); 82 msg.what = 1; //消息的标识 83 msg.obj = "A"; // 消息的存放 84 // 通过Handler发送消息到其绑定的消息队列 85 workHandler.sendMessage(msg); 86 } 87 }); 88 89 button2 = (Button) findViewById(R.id.button2); 90 button2.setOnClickListener(new View.OnClickListener() { 91 @Override 92 public void onClick(View v) { 93 Message msg = Message.obtain(); 94 msg.what = 2; 95 msg.obj = "B"; 96 workHandler.sendMessage(msg); 97 } 98 }); 99 100 } 101 102 @Override 103 protected void onDestroy() { 104 super.onDestroy(); 105 mHandlerThread.quit(); // 退出消息循环 106 workHandler.removeCallbacks(null); // 防止Handler内存泄露 清空消息队列 107 } 108 }
从上面代码可以看出,HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,然后在内部直接实现了Looper的实现,这是Handler消息机制必不可少的。有了自己的looper,可以让我们在自己的线程中分发和处理消息。如果不用HandlerThread的话,需要手动去调用Looper.prepare()和Looper.loop()这些方法。
1 //如果没有使用HandlerThread,子线程就需要中创建新的Handler 2 new Thread () { 3 @Override 4 public void run() { 5 Looper.prepare(); 6 Hnadler handler = new Handler(); 7 Looper.loop(); 8 } 9 }
①Handler是Android消息机制的上层接口,通过它可以轻松地将一个任务切换到Handler所在的线程中去执行,该线程既可以是主线程,也可以是子线程,要看构造Handler时使用的构造方法中传入的Looper位于哪里;
②Handler的运行需要底层的MessageQueue和Looper的支撑,Handler创建的时候会采用当前线程的Looper来构造消息循环系统,而线程默认是没有Looper的,如果需要使用Handler就必须为线程创建Looper;
③上述代码中的第一个Handler-mainHandler,实例化的时候,直接在onCreate()方法中new出了实例,其实是其已经在主线程中了,主线程-ActivityThread,ActivityThread被创建时就会初始化Looper,这就是主线程中默认可以直接使用Handler的原因;
④上述代码中的第二个Handler-workHandler,它在实例化的时候,参数传入了 mHandlerThread.getLooper() ,注意,这个Handler使用的就不是主线程的Looper了,而是子线程的Looper,HandlerThread在调用start()方法之后,就可以获取到子线程的Looper,然后将其传入workHandler的构造方法中,那么此时的workHandler就会运行在子线程中,用于处理耗时操作。
⑤Handler的工作原理:Handler创建时会采用当前线程的Looper来构建内部消息循环系统,如果当前线程没有Looper,那么就会报错“Can`t create handler inside thread that has not called Looper.prepare()”解决方法有两个:为当前线程创建Looper即可,像上述代码中workHandler,或者在一个有Looper的线程中创建Handler也行,就像上述代码中的mainHandler一样;
⑥调用Handler的post方法会将一个Runnable投递到Handler内部的Looper中去处理,也可以通过Handler的send方法来发送一个消息,这个消息同样会在Looper中去处理。其实post方法最终也是通过send方法来完成的。每当Looper发现有新消息到来时,就会处理这个消息,最终消息中的Runnable的run方法或者Handler的handleMessage方法就会被调用。注意Looper是运行在创建Handler所在的线程中的,这样一来Handler中的业务逻辑就被切换到创建Handler所在的线程中去执行了;
⑦Looper的工作原理:Looper在Android的消息机制中扮演着消息循环的角色,具体来说就是它会不停地从MessageQueue中查看是否有新消息,如果有新消息就会立刻处理,否则就一直阻塞在那里。注意关注一些重要的Looper的方法:
Looper.prepare()-为当前线程创建一个Looper;
Looper.loop()-开启消息循环,只有调用该方法,消息循环系统才会开始循环;
Looper.prepareMainLooper()-为主线程也就是ActivityThread创建Looper使用;
Looper.getMainLooper()-通过该方法可以在任意地方获取到主线程的Looper;
Looper.quit() Looper.quitSafely()-退出Looper,自主创建的Looper建议在不使用的时候退出
⑧ActivityThread主线程通过ApplicationThread和AMS进行进程间通信
————————————————
版权声明:本文为CSDN博主「Chin_style」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_41101173/article/details/79687313