Android中Handler、Thread、HandlerThread三者的区别
作者:Chin_style
一、前期知识储备
(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做了很多便利的封装。
———————————————————我是分割线—————————————————————
其实这个问题,最主要的关注点还是落在了HandlerThread类上,那么这个类到底有什么作用,所谓的便利封装又体现在哪里?
观察HandlerThread的官方文档的两句:①Thread. Handy class for starting a new thread that has a looper.②The looper can then be used to create handler classes.
释义:HandlerThread对象start后可以获得其Looper对象,并且使用这个Looper对象实例Handler,之后Handler就可以运行在其他线程中了。
———————————————————我是分割线—————————————————————
那么Handler和Looper到底是什么关系,为什么HandlerThread要做这样的处理?观看下图:
Andriod提供了 Handler 和 Looper 来满足线程间的通信。 Handler 先进先出原则。 Looper 类用来管理特定线程内对象之间的消息交换 (MessageExchange) 。
1)Looper: 一个线程可以产生一个 Looper 对象,由它来管理此线程里的 MessageQueue( 消息队列 ) 和对消息进行循环。
2)Handler: 你可以构造 Handler 对象来与 Looper 沟通,以便 push 新消息到 MessageQueue 里 ; 或者接收 Looper 从 Message Queue 取出 所送来的消息。
3) Message Queue( 消息队列 ): 用来存放线程放入的消息。
4) Message:是线程间通讯的消息载体。两个码头之间运输货物,Message充当集装箱的功能,里面可以存放任何你想传递的消息。
看到这里就明白了为什么:如果一个线程要处理消息,那么它必须拥有自己的Looper,并不是Handler在哪里创建,就可以在哪里处理消息。
注:对应关系Thread(1):Looper(1):MessageQueen(1):Handler(n).
三、HandlerThread的使用
正如前面所说,线程间通信的时候,比如Android中常见的更新UI,涉及到的是子线程和主线程之间的通信,实现方式就是Handler+Looper,但是要自己手动操作Looper,不推荐,所以谷歌封装了HandlerThread类(类似于AsyncTask类)。
上代码,具体实现:
public class MainActivity extends AppCompatActivity { Handler mainHandler,workHandler; HandlerThread mHandlerThread; TextView text; Button button1,button2; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text = (TextView) findViewById(R.id.text1); // 创建与主线程关联的Handler mainHandler = new Handler(); /** * 步骤①:创建HandlerThread实例对象 * 传入参数 = 线程名字,作用 = 标记该线程 */ mHandlerThread = new HandlerThread("handlerThread"); /** * 步骤②:启动线程 */ mHandlerThread.start(); /** * 步骤③:创建工作线程Handler & 复写handleMessage() * 作用:关联HandlerThread的Looper对象、实现消息处理操作 & 与其他线程进行通信 * 注:消息处理操作(HandlerMessage())的执行线程 = mHandlerThread所创建的工作线程中执行 */ workHandler = new Handler(mHandlerThread.getLooper()){ @Override public void handleMessage(Message msg) { //设置了两种消息处理操作,通过msg来进行识别 switch(msg.what){ case 1: try { //延时操作 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } // 通过主线程Handler.post方法进行在主线程的UI更新操作 mainHandler.post(new Runnable() { @Override public void run () { text.setText("第一次执行"); } }); break; case 2: try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } mainHandler.post(new Runnable() { @Override public void run () { text.setText("第二次执行"); } }); break; default: break; } } }; /** * 步骤④:使用工作线程Handler向工作线程的消息队列发送消息 * 在工作线程中,当消息循环时取出对应消息 & 在工作线程执行相关操作 */ button1 = (Button) findViewById(R.id.button1); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Message msg = Message.obtain(); msg.what = 1; //消息的标识 msg.obj = "A"; // 消息的存放 // 通过Handler发送消息到其绑定的消息队列 workHandler.sendMessage(msg); } }); button2 = (Button) findViewById(R.id.button2); button2.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Message msg = Message.obtain(); msg.what = 2; msg.obj = "B"; workHandler.sendMessage(msg); } }); } @Override protected void onDestroy() { super.onDestroy(); mHandlerThread.quit(); // 退出消息循环 workHandler.removeCallbacks(null); // 防止Handler内存泄露 清空消息队列 } }
从上面代码可以看出,HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,然后在内部直接实现了Looper的实现,这是Handler消息机制必不可少的。有了自己的looper,可以让我们在自己的线程中分发和处理消息。如果不用HandlerThread的话,需要手动去调用Looper.prepare()和Looper.loop()这些方法。
// 子线程中创建新的Handler 没有使用HandlerThread new Thread () { @Override public void run() { Looper.prepare(); Hnadler handler = new Handler(); Looper.loop(); } }
提供一些其他Android消息机制分析,帮助理解读者理解:
①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进行进程间通信
到此这篇关于Android中Handler、Thread、HandlerThread三者的区别的文章就介绍到这了,更多相关Android中Handler、Thread、HandlerThread三者的区别内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!