handler消息机制详解
来源:互联网 发布:手机网络翻墙怎么回来 编辑:程序博客网 时间:2024/06/06 02:07
在日常开发中我们经常用到hanlder来更新ui界面或者传递消息,他主要用于线程之间的通信,之前一直就这么用,对于他的深层原理并没有深究,在周五的项目中又再次用到了,现在在这里来深入分析下。
运行原理:
在android4.0之后,为了保证正主线程的流畅性,不能再主线程访问网络或者加载耗时间的数据,对于这写操作统一放到了子线程中进行,而在主线程中主要进行ui界面的更新,这时候我们就需要借助于handler消息机制在子线程与主线程之间相互通信这个过程比较复杂,主要涉及到四大要素:
- Message(消息)
- MessageQueue(消息队列)
- Looper(消息循环)
- Handler(消息发送和处理)
Looper:
looper是一个轮询器,它也存在于主线程和子线程中,当handler初始化好的时候,就和当前所在的线程的handler绑定。他的作用的不断地循环,当发现消息队列里面有数据的时候就会立即从消息队列里面取出来,当没有消息时候就会暂停下来。需要注意的是handler的创建必须借助looper,在主线程中,系统人默认会创建一个looper轮询器,而在子线程中,需要手动创建。
new Thread(new Runnable() { @Override public void run() { Looper.prepare(); Handler handler = new Handler(); Looper.loop(); } }).start();
Looper中还有一个特殊的概念,那就是ThreadLocal,每一个线程,都会单独对应的一个looper,这个looper通过ThreadLocal来创建,保证每个线程只创建一个looper,looper初始化后就会调用looper.loop创建一个MessageQueue,这个方法在UI线程初始化的时候就会完成,我们不需要手动创建。ThreadLocal并不是线程,它的作用是可以在每个线程中存储数据。Handler内部如何获取到当前线程的Looper呢?这就要使用ThreadLocal了,ThreadLocal可以在不同的线程之中互不干扰地存储并提供数据,通过ThreadLocal可以轻松获取每个线程的Looper。当然需要注意的是,线程是默认没有Looper的,如果需要使用Handler就必须为线程创建Looper。
MessageQueue:消息队列它是用来存放消息的一个队列结构,当子线程或者主线程通过handler发送消息时候,他都会把消息按照先后顺序存放起来,读取的时候是按照消息的先后顺序进行读取,在读取完成之后伴随着着消息的移除。存放、读取、移除三者是同步进行的,先存放,后读取,再移除,这个读取是靠looper不断地循环读取的。接下来看看message的创建,和一些常用的方法:
1、message的创建
通过阅读源码发现,message他实现了Parcelable接口,创建有两种方式一种是直接 new Message();另外一种是使用Message的静态方法obtain来获取,这两种方法的区别是第一种直接通过创建对象来获取message,这种方法不推荐,第二种是从message的消息池里面取得。 它类似一个线程池,创建了一个Message池,如果有闲置的Message就直接返回,不然就新建一个,用完以后,返回消息池,这种方法大大减少了当有大量Message对象而产生的垃圾回收问题吗,并且他还提供了大量形式的构造方法供我们来使用。Message.obtain()的消息池上限是10个。
public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }
从以上源码中我们可以看出obtain方法的内部结构是一个消息池。
2、Message的常用方法;
(1)what:int类型的数据,用于指定消息的类型,标记消息从哪里来。
(2)arg0,arg1:两个int型值,一般用来传递简单的整型数据。
(3)obj:object类型的数据,用于传递复杂的数据。
(4)data:Bundle型,这个传递较多种数据的时候需要用到。
Handler:
handler它是一个在线程之间通讯的桥梁,充当了子线程与主线程之间的沟通的媒介。他不但存在于主线程,并且还存在于子线程,也就是说每个线程都存在handler,当我们创建handler时候,可以在其构造方法中指定他的线程,也可以不指定,当不指定,即构造方法为空的时候他默认是存在于当前线程。
1、 HandlerThread详解HandlerThread本质上还是一个thread,他继承自thread,内部封装了looper。HandlerThread与handler的区别是:handler与activity在同个线程中,而HandlerThread与activity在不同线程中。HandlerThread将loop转到子线程中处理,降低了主线程的压力,使主界面更流畅。使用步骤如下:
(1)创建一个HandlerThread,即创建了一个包含Looper的线程。
HandlerThread handlerThread = new HandlerThread("sohu.com");
handlerThread.start(); //创建HandlerThread后一定要记得start(),获取HandlerThread的Looper
(2)Looper looper = handlerThread.getLooper();创建Handler,通过Looper初始化
(3)Handler handler = new Handler(looper);
通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。
如果想让HandlerThread退出,则需要调用handlerThread.quit();。
2、handler中更新ui界面的方法(1)sendMessage发送
private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { if (msg.what == 1) { Toast.makeText(getApplicationContext(), string, Toast.LENGTH_LONG).show(); } } };
(2)使用post发送消息(延迟消息)
private Handler handler = new Handler(); Runnable runnable = new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(),string, Toast.LENGTH_LONG).show(); } }; handler.post(runnable);(3)使用runOnUiThread更新
new Thread(){ @Override public void run() { //在这里进行复杂的数据操作 // ………………………………………………………………………… runOnUiThread(new Runnable() { @Override public void run() { //在这里进行更新UI的操作 Toast.makeText(getApplicationContext(),string, Toast.LENGTH_LONG).show(); } }); } }.start();
以上三种方法均是使用主线程的handler向主线程发消息,那么在线程如何获取handler,并向主线程发消息呢?在上文提到在创建handler时候需要借助于looper,主线程默认有点,子线程是默认没有的,需要我没自己创建,因此必须创建,否则会报handler没有初始化的错误,下面来看看代码:
Looper.prepare(); Handler handler = new Handler() { @Override public void handleMessage(Message msg) { Toast.makeText(context, "发送消息成功!", Toast.LENGTH_SHORT).show(); } }; handler.sendEmptyMessage(1); //一定要写这个标记,要不然收不到 Looper.loop();
注意:handler使用不当可能会导致内存泄漏,所以在handler使用结束的时候需要在移除消息。handler.removeCallbacksAndMessages(null);即可移除消息。
- Handler消息机制详解
- handler消息机制详解
- Android Handler 消息机制详解
- 深入理解Handler消息传递机制详解
- Handler消息(Message)传递机制详解
- Android Handler异步消息机制详解
- Android之Handler消息机制详解
- Android中Handler传递消息机制详解
- Android Handler消息处理机制详解
- Android的消息机制Handler详解
- Android Handler消息传递机制详解
- Android消息机制Handler的原理详解
- Android Handler消息处理机制详解
- Android基础_详解Handler消息机制
- Android 异步消息机制 Handler Message Looper机制详解
- Handler消息传递机制
- Handler 消息传递机制
- handler消息机制
- 解决 java.net.SocketException: sendto failed: ECONNRESET (Connection reset by peer) 异常
- React入门记事本小项目(二)
- ARM体系当中汇编和C混编传参的规则
- 密码学的那些事儿
- spring boot实战笔记
- handler消息机制详解
- macOS sierra安装cocoapods
- Access restriction: The type 'XXX' is not API (restriction on required library 'C:\Progra
- Linux Shell之sed命令
- Handler一定要在主线程实例化吗?new Handler()和new Handler(Looper.getMainLooper())的区别
- weblogic性能优化
- jQuery幻灯片插件Vmc Slider 实例
- 读书笔记 · Accelerated C++ 一
- 数据字典开发使用