Android必备知识点之消息传递机制Handler
1.最常见的使用场景
Android中常用Handler使用场景?
并不能在子线程中访问UI控件,否则会触发程序异常,这时候需要通过Handler将更新UI的操作切换到主线程进行
系统为什么不允许在子线程中访问UI呢?
UI控件不是线程安全的,多线程并发访问的时候可能会导致UI处于不可预期的状态,如果对UI控件的访问加线程锁,会降低UI线程的访问效率,另外就是逻辑变的复杂。
简要概括:
Handler运行需要底层MessageQueue 和 Looper支撑
MessageQueue:消息队列,内部存储一组消息,一对队列的形式对外提供插入和删除的工作。内部存储结构不是队列,而是单链表
Looper:消息循环,MessageQueue只是消息的存储单元,不能处理消息,Looper则无限循环查询消息,如果有新消息,则处理,否则一直等待。
ThreadLocal:并不是线程,它的作用是在每个线程中存储数据。
Handle创建的时候会才用当前线程的Looper来构造消息循环系统,Handler是怎么获得当前线程的呢?是因为使用了ThreadLocal,它可以在不同的线程中存储并提供数据,通过ThreadLocal可以轻松获取每个线程的Looper。
ThreadLocal详解
ThreadLocal是一个线程内部存储类,通过他可以在指定的线程中存储数据,数据存储以后,只有在指定线程中可以获取到存储的数据,对于其他线程则无法获取到数据。
1.使用场景:
①以线程为作用域并且不同的线程具有不同的数据副本。
②复杂逻辑下的对象传递,例如监听器的传递。通过参数传递或者静态全局变量,都有局限性
2.使用
ThreadLocal<T> mtL = new ThreadLocal<T>();
//设置
mtl.set("..");
//获取
mtl.get();
3.源码解析
public void set(T value) {
Thread currentThrea = Thread.currentThread();
Values values = values(currentThread);
if(values == null) {
values = initializeValues(currentThrea);
}
values.put(this,value);
}
通过valuse方法获取当前线程中的ThreadLocal数据,没有则初始化,然后再讲ThreadLocal的值进行存储,数组形式的存储,这里数组排列顺序:所有的线程有一个排序,这个排序,存储数据是当前线程排序下角标加一。具体就不深入了~
Looper详解
new Thread(new Runnable() {
@Override
public void run() {
//为当前线程创建looper
Looper.prepare();
Handler handler = new Handler();
//开启消息循环
Looper.loop();
}
}).start();
①Looper.quit()和Looper.quitSafely()的区别
quit会直接退出Looper,而quitSafely只是设定一个退出标记,然后把消息队列中的已有的消息处理完毕才安全的退出。
解析:
①Looper.prepare()
此方法会调用Looper(boolea quitAllowed)创建Looper,
private Looper(boolea quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
持有当前线程和MessageQueue;
②Looper.loop()
代码过于长就不粘贴了,大概解析一下
....
for(;;){
Message msg = mQueue.next();
if(msg == null) {
return;
}
...
msg.target.dispatchMessage(msg);
...
}
loop方法是个死循环,唯一跳出的方式就是MessageQueue的next方法返回null,即当调用Looper.quit()和Looper.quitSafely(),next为空,消息队列退出。也就是说,如果Looper必须退出吗,否则一直循环。
处理消息:msg.target.dispatchMessage(msg);其中msg.target是发送这条消息的Handler的对象,也就是说,消息最终交给dispatchMessage方法处理
Handler的工作原理
handler.sendMessage(Message msg); –> sendMessageDelayed(Message msg,long 0); –> sendMessageAtTime(Message msg, long delaymillis) –> enqueueMessage(MessageQueue queue, Message msg, long delaymillis)
Handler发送消息是向消息队列中插入一条消息,MessageQueue的next方法就会返回这条消息给Looper,Looper收到消息后就开始处理了,最终消息由Looper交由Handler处理,即Handler的dispatchMessage方法会被调用,这时Handler就进入处理消息阶段了,调用handleCallBack(msg)
抽象方法
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
Handler和Handler.Callback的handleMessage区别:
如果直接用Handler的handleMessage黄色警报,换成静态的就好了,原因:MessageQueue中的消息队列会一直持有对handler的引用,而作为内部类的handler会一直持有外部类的引用,就会导致外部类不能被GC回收。当我们发延时很长的msg时就容易出现泄漏。所以此处应该设置为static,然后Handler就会跟随类而不是跟随类的对象加载,也就不再持有外部类的对象引用。
handler.post(new Runnable(){
@Override
public void run() {
mTestTV.setText("This is post");//更新UI
}});
和handler.sendMessage(msg);作用相当
推荐阅读
-
android线程消息机制之Handler详解
-
Android Studio 之 Android消息机制 之简单Demo --- 使用Handler和Message类来完成消息传递
-
Android技术点记录-handler消息传递机制
-
Android必备知识点之View及View的事件分发机制
-
Handler异步消息传递机制(四)Handler发送消息流程,源码(Android 9.0)彻底解析
-
Android消息机制三剑客之Handler、Looper、Message源码分析(一)
-
Android消息机制原理,仿写Handler Looper源码解析跨线程通信原理--之仿写模拟Handler(四)
-
Android中的消息机制:Handler消息传递机制
-
Android开发之消息处理机制(一)——Handler
-
Handler Looper源码解析(Android消息传递机制)