介绍Handler、Looper、MessageQueue、ThreadLocal和主线程ActivityThread等内容
Android的消息机制
版本:2018/2/6-1
消息机制概述
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
就必须为线程创建Looper
UI线程
就是ActivityThread
,被创建时会初始化Looper
,因此UI线程
中默认是可以使用Handler
的
6、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
- 如果当前线程没有
Looper
就会报错,要么创建Looper
,要么在有Looper
的线程中创建Handler
Handler
的post
方法会将一个Runnable
投递到Handler
内部的Looper
中处理(本质也是通过send
方法完成)Handler
的send
方法被调用时,会调用MessageQueue
的enqueueMessage
方法将消息放入消息队列, 然后Looper
发现有新消息到来时,就会处理这个消息,最终消息中的Runnable
或者Handler
的handleMessage
就会被调用- 因为
Looper
是运行在创建Handler
所在的线程中的,所以Handler
中的业务逻辑就会被切换到创建Handler
所在的线程中
ThreadLocal
8、ThreadLocal的作用
ThreadLocal
是线程内部的数据存储类,可以在指定线程中存储数据,之后只有在指定线程中才开业读取到存储的数据- 应用场景1:某些数据是以线程为作用域,并且不同线程具有不同的数据副本的时候。
ThreadLocal
可以轻松实现Looper
在线程中的存取。- 应用场景2:在复杂逻辑下的对象传递,通过
ThreadLocal
可以让对象成为线程内的全局对象,线程内部通过get
就可以获取。
9、ThreadLocal的使用
mBooleanThreadLocal.set(true);
Log.d("ThreadLocal", "[Thread#main]" + mBooleanThreadLocal.get());
new Thread("Thread#1"){
@Override
public void run(){
mBooleanThreadLocal.set(true);
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
中输出null
ThreadLocal
内部会从各自线程中取出数组,再根据当前ThreadLocal
的索引去查找出对应的value
值。
10、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);
//2. 根据当前ThreadLocal获取到Hash key,并以此从table中查询出Entry
for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
//3. 如果Entry的ThreadLocal与当前的ThreadLocal相同,则用新值覆盖e的value
if (k == key) {
e.value = value;
return;
}
//4. Entry没有ThreadLocal则把当前ThreadLocal置入,并存储value
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
//5. 没有查询到Entry,则新建Entry并且存储value
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
//ThreadLocal内部类ThreadLocalMap的静态内部类
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
11、ThreadLocal的get()源码分析
public T get() {
//1. 获取当前线程对应的ThreadLocalMap
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
//2. 取出map中的对应该ThreadLocal的Entry
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
//3. 获取到entry后返回其中的value
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//4. 没有ThreadLocalMap或者没有获取到ThreadLocal对应的Entry,返回规定数值
return setInitialValue();
}
private T setInitialValue() {
//1. value = null
T value = initialValue();//返回null
Thread t = Thread.currentThread();
//2. 若不存在则新ThreadLocalMap, 在里面以threadlocal为key,value为值,存入entry
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
- 当前线程对应了一个
ThreadLocalMap
- 当前线程的
ThreadLocal
对应一个Map中的Entry
(存在table中)Entry
中key
会获取其对应的ThreadLocal,value
就是存储的数值
消息队列: MessageQueue
12、MessageQueue的主要操作
enqueueMessage
: 往消息队列中插入一条消息next
:取出一条消息,并且从消息队列中移除- 本质采用
单链表
的数据结构来维护消息队列,而不是采用队列
13、MessageQueue的插入和读取源码分析
//MessageQueue.java:插入数据
boolean enqueueMessage(Message msg, long when) {
//1. 主要就是单链表的插入操作
synchronized (this) {
......
}
return true;
}
/**==========================================
* 功能:读取并且删除数据
* 内部是无限循环,如果消息队列中没有消息就会一直阻塞。
* 一旦有新消息到来,next方法就会返回该消息并且将其从单链表中移除
*===========================================*/
Message next() {
for (;;) {
......
}
}
Looper
14、Looper的构造
private Looper(boolean quitAllowed) {
//1. 会创建消息队列: MessageQueue
mQueue = new MessageQueue(quitAllowed);
//2. 当前线程
mThread = Thread.currentThread();
}
15、为线程创建Looper
//1. 在没有Looper的线程创建Handler会直接异常
new Thread("Thread#2"){
@Override
public void run(){
Handler handler = new Handler();
}
}.start();
异常:
java.lang.RuntimeException: Can’t create handler inside thread that has not called Looper.prepare()
//2. 用prepare为当前线程创建一个Looper
new Thread("Thread#2"){
@Override
public void run(){
Looper.prepare();
Handler handler = new Handler();
//3. 开启消息循环
Looper.loop();
}
}.start();
16、主线程ActivityThread中的Looper
- 主线程中使用
prepareMainLooper()
创建Looper
getMainLooper
能够在任何地方获取到主线程的Looper
17、Looper的退出
Looper
的退出有两个方法:quit
和quitSafely
quit
会直接退出Looper
quitSafely
只会设置退出标记,在已有消息全部处理完毕后才安全退出Looper
退出后,Handler
的发行的消息会失败,此时send
返回false
子线程
中如果手动创建了Looper
,应该在所有事情完成后调用quit
方法来终止消息循环
18、Looper的loop()源码分析
//Looper.java
public static void loop() {
//1. 获取Looper
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
//2. 获取消息队列
final MessageQueue queue = me.mQueue;
......
for (; ; ) {
//3. 获取消息,如果没有消息则会一直阻塞
Message msg = queue.next();
/**=================================
* 4. 如果消息获得为null,则退出循环
* -Looper退出后,next就会返回null
*=================================*/
if (msg == null) {
return;
}
......
/**==========================================================
* 5. 处理消息
* -msg.target:是发送消息的Handler
* -最终在该Looper中执行了Handler的dispatchMessage()
* -成功将代码逻辑切换到指定的Looper(线程)中执行
*========================================================*/
msg.target.dispatchMessage(msg);
......
}
}
Handler
19、Handler的post/send()源码分析
//Handler.java: post最终是通过send系列方法实现的
//Handler.java
public final boolean sendMessage(Message msg)
{
return sendMessageDelayed(msg, 0);
}
//Handler.java
public final boolean sendMessageDelayed(Message msg, long delayMillis)
{
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//Handler.java
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
//Handler.java
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//1. 最终是向消息队列插入一条消息
return queue.enqueueMessage(msg, uptimeMillis);
}
sendMessage()
会将消息插入到消息队列中
MessageQueue
的next
方法就会返回这条消息交给Looper
- 最终
Looper
会把消息交给Handler
的dispatchMessage
20、Handler的消息处理源码
//Handler.java
public void dispatchMessage(Message msg) {
//1. Msg的callback存在时处理消息——Handler的post所传递的Runnable
if (msg.callback != null) {
handleCallback(msg);
} else {
/**===============================================
*2. mCallback不为null时调用handleMessage
* -Handler handle = new Handler(callback)
* -好处在于不需要派生Handler子类并且也不需要重写其handleMessage
*=============================================*/
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//3. 如果其他条件都不符合,最后会调用Handler的handleMessage进行处理
handleMessage(msg);
}
}
//Handler.java-调用Handler的post所传递的Runnable的run()方法
private static void handleCallback(Message message) {
message.callback.run();
}
//Handler.java-Callback接口用于不需要派生Handler就能完成功能
public interface Callback {
public boolean handleMessage(Message msg);
}
21、Handler的特殊构造方法
Handler handle = new Handler(callback);
-不需要派生Handler- 通过特定
Looper
构造Handler
public Handler(Looper looper) {
this(looper, null, false);
}
- 默认构造函数
public Handler(Callback callback, boolean async) {
......
mLooper = Looper.myLooper();
//1. 在没有Looper的线程中创建Handler
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
主线程的消息循环
22、主线程ActivityThread的消息循环
//ActivityThread.java
public static void main(String[] args) {
//1. 创建主线程的Looper和MessageQueue
Looper.prepareMainLooper();
......
//2. 开启消息循环
Looper.loop();
}
/**=============================================
* ActivityThread中需要Handler与消息队列进行交互
* -内部定义一系列消息类型:主要有四大组件等
* //ActivityThread.java
*=============================================*/
private class H extends Handler {
public static final int LAUNCH_ACTIVITY = 100;
public static final int PAUSE_ACTIVITY = 101;
public static final int PAUSE_ACTIVITY_FINISHING= 102;
......
}
ActivityThread
通过ApplicationThread
和AMS
进行IPC通信
AMS
完成请求的工作后会回调ApplicationThread
中的Binder
方法ApplicationThread
会向Handler H
发送消息H
接收到消息后会将ApplicationThread
的逻辑切换到ActivityThread
中去执行