转载请注明链接:https://blog.youkuaiyun.com/feather_wch/article/details/79263855
详解Handler消息机制,包括Handler、MessageQueue、Looper和LocalThread。
本文是我一点点归纳总结的干货,但是难免有疏忽和遗漏,希望不吝赐教。
Handler消息机制详解(29题)
版本:2018/9/7-1(2359)
问题汇总
以问答形式将本文的所有内容进行汇总。考考你哟。
- Handler是什么?
- 消息机制是什么?
- MeesageQueue是什么?
- Looper是什么?
- ThreadLocal是什么?
- 为什么不能在子线程中访问UI?
- Handler的运行机制概述(Handler的创建、Looper的创建、MessageQueue的创建、以及消息的接收和处理)
- 主线程向子线程发送消息的方法?
- ThreadLocal的作用?
- ThreadLocal的应用场景
- ThreadLocal的使用
- ThreadLocal的set()源码分析
- ThreadLocal的get()源码分析
- MessageQueue的主要操作
- MessageQueue的插入和读取源码分析
- MessageQueue的next源码详解
- Looper的构造中做了什么?
- 子线程中如何创建Looper?
- 主线程ActivityThread中的Looper是如何创建和获取的?
- Looper如何退出?
- quit和quitSafely的区别
- Looper的loop()源码中的4个工作?
- Android如何保证一个线程最多只能有一个Looper?
- Looper的构造器为什么是private的?
- Handler消息机制中,一个looper是如何区分多个Handler的?
- 主线程ActivityThread的消息循环
- ActivityThread中Handler H是做什么的?
- Handler的post/send()逻辑流程
- Handler的postDelayed逻辑流程
- Handler的消息处理的流程?
- Handler的特殊构造方法中,为什么有Callback接口?
- Handler的内存泄漏如何避免?
消息机制概述(8)
1、Handler是什么?
- Android消息机制的上层接口(从开发角度)
- 能轻松将任务切换到Handler所在的线程中去执行
- 主要目的在于解决在子线程中无法访问UI的矛盾
2、消息机制?
Android的消息机制主要就是指Handler的运行机制Handler的运行需要底层MessageQueue和Looper的支撑
3、MeesageQueue是什么?
- 消息队列
- 内部存储结构并不是真正的队列,而是单链表的数据结构来存储消息列表
- 只能存储消息,而不能处理
4、Looper是什么?
- 消息循环
Looper以无限循环的形式去查找是否有新消息,有就处理消息,没有就一直等待着。
5、ThreadLocal是什么?
Looper中一种特殊的概念ThreadLocal并不是线程,作用是可以在每个线程中互不干扰的存储数据和提供数据。Handler创建时会采用当前线程的Looper来构造消息循环系统,Handler内部就是通过ThreadLocal来获取当前线程的Looper的- 线程默认是没有
Looper的,如果需要使用Handler就必须为线程创建LooperUI线程就是ActivityThread,被创建时会初始化Looper,因此UI线程中默认是可以使用Handler的
6、为什么不能在子线程中访问UI?
ViewRootImpl会对UI操作进行验证,禁止在子线程中访问UI:
void checkThread(){
if(mThread != Thread.currentThread()){
throw new CalledFromWrongThreadException("Only th original thread that created a view hierarchy can touch its views");
}
}
7、Handler的运行机制概述(Handler的创建、Looper的创建、MessageQueue的创建、以及消息的接收和处理)
- Handler创建时会采用当前线程的Looper
- 如果当前线程没有
Looper就会报错,要么创建Looper,要么在有Looper的线程中创建HandlerHandler的post方法会将一个Runnable投递到Handler内部的Looper中处理(本质也是通过send方法完成)Handler的send方法被调用时,会调用MessageQueue的enqueueMessage方法将消息放入消息队列, 然后Looper发现有新消息到来时,就会处理这个消息,最终消息中的Runnable或者Handler的handleMessage就会被调用- 因为
Looper是运行在创建Handler所在的线程中的,所以通过Handler执行的业务逻辑就会被切换到Looper所在的线程中执行。
8、主线程向子线程发送消息的方法?
- 通过在主线程调用子线程中Handler的post方法,完成消息的投递。
- 通过
HandlerThread实现该需求。
ThreadLocal(4)
1、ThreadLocal的作用
ThreadLocal是线程内部的数据存储类,可以在指定线程中存储数据,之后只有在指定线程中才开业读取到存储的数据- 应用场景1:某些数据是以线程为作用域,并且不同线程具有不同的数据副本的时候。
ThreadLocal可以轻松实现Looper在线程中的存取。- 应用场景2:在复杂逻辑下的对象传递,通过
ThreadLocal可以让对象成为线程内的全局对象,线程内部通过get就可以获取。
2、ThreadLocal的使用
mBooleanThreadLocal.set(true);
Log.d("ThreadLocal", "[Thread#main]" + mBooleanThreadLocal.get());
new Thread("Thread#1"){
@Override
public void run(){
mBooleanThreadLocal.set(false);
Log.d("ThreadLocal", "[Thread#1]" + mBooleanThreadLocal.get());
}
}.start();
new Thread("Thread#2"){
@Override
public void run(){
Log.d("ThreadLocal", "[Thread#2]" + mBooleanThreadLocal.get());
}
}.start();
- 最终
main中输出true;Thread#1中输出false;Thread#2中输出nullThreadLocal内部会从各自线程中取出数组,再根据当前ThreadLocal的索引去查找出对应的value值。
3、ThreadLocal的set()源码分析
//ThreadLocal.java
public void set(T value) {
//1. 获取当前线程
Thread t = Thread.currentThread();
//2. 获取当前线程对应的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null)
//3. map存在就进行存储
map.set(this, value);
else
//4. 不存在就创建map并且存储
createMap(t, value);
}
//ThreadLocal.java内部类: ThreadLocalMap
private void set(ThreadLocal<?> key, Object value) {
//1. table为Entry数组
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);

本文详细剖析了Android中的Handler消息机制,涵盖Handler、MessageQueue、Looper和ThreadLocal的概念及工作原理。通过问答形式,解释了为何不能在子线程中访问UI、Handler的运行机制、如何在子线程中发送消息到主线程等问题。同时,文章探讨了ThreadLocal的作用及其在消息机制中的应用,以及如何避免Handler引发的内存泄漏问题。
最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



