1.前言
Handler不管是作为一种消息机制,还是作为切换线程的手段,在Android中都有充足的应用场景,因为一个APP的运行过程,是不断接受消息以及处理消息的过程。比如Activity,从启动、创建、生命周期回调、销毁,都是借由Handler发送消息来驱动完成。从一个APK的安装,到一个View的更新,都离不开Handler的帮助。
2.Handler用法
class MainActivity : AppCompatActivity() {
//创建handler实例,并实现构造方法中接口Handler.Callback
private val handler = Handler(Handler.Callback {
//打印出当前线程名字以及数据arg1
Log.e(
"TAG",
"handleMessage -> ThreadName : ${Thread.currentThread().name} + Handler.arg1 : ${it.arg1}"
)
false
})
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//创建一个子线程
Thread {
Log.e("TAG", "ThreadName : ${Thread.currentThread().name}")
//创建一个message
val message = Message.obtain()
//给message的arg赋值
message.arg1 = 3
//通过handler发送消息message
handler.sendMessage(message)
}.start()
}
}
运行结果
3.Handler源码分析
handler.png-
ActivityThread
APP进程的初始类,它的main
函数是APP进程的入口,代表了主线程,但不是一个Thread
类,它是主线程操作的管理者,与AMS
交互并管理Activity
和Service
public final class ActivityThread extends ClientTransactionHandler {
...
// 仅贴出关键源码
public static void main(String[] args) {
... // 仅贴出关键代码
//1. 为主线程创建1个Looper对象,同时生成1个消息队列对象(MessageQueue)
//注: 最终调用prepare() 中 sThreadLocal.set(new Looper(quitAllowed)); 创建Looper对象
Looper.prepareMainLooper();
//2.创建主线程
ActivityThread thread = new ActivityThread();
//自动开启消息循环
Looper.loop();
}
}
这就解释了为什么主线程在使用handler
的时候不需要Loopre.prepare()
和 Looper.loop()
了,而子线程需要?这是因为在应用启动的时候ActivityThread
已经调用过了。
-
ThreadLocal
从名字我们就可以看到ThreadLocal
叫做线程变量,意思是ThreadLocal
中填充的变量属于当前线程,该变量对其他线程而言是隔离的。ThreadLocal
为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。在这里可以简单的理解为它内部维护了一个map<Thread,Looper>
,key
为当前线程,value
为当前线程绑定的Loop
对象
public class ThreadLocal<T> {
public T get() {
//获取当前线程
Thread t = Thread.currentThread();
//获取以线程为key的map
ThreadLocalMap map = getMap(t);
//判断map是否为空
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//若为空,则初始化value
return setInitialValue();
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
private T setInitialValue() {
//initialValue() 默认值返回null
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
// t.threadLocals = new ThreadLocalMap(this, firstValue);
//创建一个ThreadLocalMap
createMap(t, value);
//返回默认值null
return value;
}
}
- Looper
public final class Looper {
//构造方法 quitAllowed为标志,true:子线程 false:主线程
private Looper(boolean quitAllowed) {
// 1. 创建1个消息队列对象(MessageQueue)
// 即 当创建1个Looper实例时,会自动创建一个与之配对的消息(MessageQueue)
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
//主线程调用
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
//主线程的Looper对象
sMainLooper = myLooper();
}
}
//子线程调用
public static void prepare() {
prepare(true);
}
//sThreadLocal 赋值 子线程和主线程最终都调用到此处(必须调用)
private static void prepare(boolean quitAllowed) {
// 1. 判断sThreadLocal是否为null,否则抛出异常
//即 Looper.prepare()方法不能被调用两次 = 1个线程中只能对应1个Looper实例
// 注:sThreadLocal = 1个ThreadLocal对象,用于存储线程的变量
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 2. 若为初次Looper.prepare(),则创建Looper对象 & 存放在ThreadLocal变量中
// 注:Looper对象是存放在Thread线程里的
// 源码分析Looper的构造方法
//quitAllowed为标志,true:子线程 false:主线程
sThreadLocal.set(new Looper(quitAllowed));
}
//获取当前线程的Looper对象
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
//开启循环器(必须调用)
public static void loop() {
...// 仅贴出关键代码
//1.获取当前线程的Looper
final Looper me = myLooper();
// myLooper()作用:返回sThreadLocal存储的Looper实例;若me为null 则抛出异常
// 即loop()执行前必须执行prepare(),从而创建1个Looper实例
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
// 获取Looper实例中的消息队列对象(MessageQueue)
final MessageQueue queue = me.mQueue;
//2. 消息循环(通过for循环)
//这里会有个小疑问,同样是死循环,为什么不用while () 而使用 for (;;)
// while(true) 编译后 mov eax,1 for (;;)编译后 jmp wmain+29h
// test eax,eax
// je wmain+29h
// jmp wmain+1Eh
//由上面的结果可以看出for编译器会优化成一条汇编指令,而while编译器会有很多条汇编指令
// 结果:for ( ; ; )指令少,不占用寄存器,而且没有判断、跳转
for (;;) {
//2.1 从消息队列中取出消息,下面messageQueue马上分析
// next():取出消息队列里的消息
// 若取出的消息为空,则线程阻塞
Message msg = queue.next(); // might block
// 2.2 派发消息到对应的Handler
// 把消息Message派发给消息对象msg的target属性
// target属性实际是1个handler对象
msg.target.dispatchMessage(msg);
// 3. 释放消息占据的资源
msg.recycleUnchecked();
}
}
}
- MessageQueue
//单链表的消息队列
public final class MessageQueue {
//出队消息,即从 消息队列中 移出该消息
Message next() {
...// 仅贴出关键代码
// 该参数用于确定消息队列中是否还有消息
// 从而决定消息队列应处于出队消息状态 or 等待状态
int nextPollTimeoutMillis = 0;
for (;;) {
//nativePollOnce方法在native层,若是nextPollTimeoutMillis为-1,此时消息队列处于等待状态。
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// 获取当前时间
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//是否开启异步处理消息的(优先处理)
if (msg != null && msg.target == null) {
// Stalled by a barrier. Find the next asynchronous message in the queue.
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
// 出队消息,即 从消息队列中取出消息:按创建Message对象的时间顺序
if (msg != null) {
//判断当前时间与消息的时间比较
if (now < msg.when) {
// 计算距离下个消息所需时间
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 开始取消息
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
//链表删除
msg.next = null;
msg.markInUse();
//返回消息
return msg;
}
} else {
// 若 消息队列中已无消息,则将nextPollTimeoutMillis参数设为-1
// 下次循环时,消息队列则处于等待状态
nextPollTimeoutMillis = -1;
}
}
}
}
//作用:入队,即 将消息 根据时间 放入到消息队列中(Message ->> MessageQueue)
//采用单链表实现:提高插入消息、删除消息的效率
boolean enqueueMessage(Message msg, long when) {
...// 仅贴出关键代码
synchronized (this) {
msg.when = when;
//获得链表头
Message p = mMessages;
boolean needWake;
// 判断消息队列里有无消息
// a. 若无,则将当前插入的消息 作为队头 & 若此时消息队列处于等待状态,则唤醒
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
//如果表头为空,消息为即时消息,表头时间大于插入消息
msg.next = p;
//直接插入消息到表头
mMessages = msg;
needWake = mBlocked;
} else {
// Inserted within the middle of the queue. Usually we don't have to wake
// up the event queue unless there is a barrier at the head of the queue
// and the message is the earliest asynchronous message in the queue.
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// b. 判断消息队列里有消息,则根据 消息(Message)创建的时间 插入到队列中
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
}
总结下流程:
- 当我们启动应用时最先启动的是
ActivityThread
中的main()
方法。 -
main()
里面调用Looper.prepareMainLooper()
标识了主线程quitAllowed
,最终调用prepare()
方法的sThreadLocal.set(new Looper(quitAllowed))
。解释一下,sThreadLocal里面有个map
,key
为线程,value
为looper
,一个线程对应唯一个Looper。在此处创建并绑定当前线程的Looper
。 -
Looper
构造方法为私有的,并且里面创建了一个MessageQueue
对象,所以Looper
也是唯一绑定在Looper
里面的。 -
1,2,3
小结:创建一个Map<Therad,Looper>
,并设置数据创建Looper
,通过Looper
构造方法绑定MessageQueue
。 -
main()
最后还调用了Looper.loop()
启动循环器,通过myLooper()
获取当前线程MessageQueue
消息队列,在死循环里不断调用queue.next()
获取消息,最后通过msg.target.dispatchMessage(msg)
分发消息到handler中。 -
MessageQueue.next()
通过死循环不断的从链表中读取消息,没有消息时则通过nativePollOnce
方法来阻塞线程。 -
5,6
小结:通过调用Looper.loop()
方法不断从MessageQueue.next()
里读取消息,然后通过handler.dispatchMessage(Message msg)
把消息分发出去。 - 至此除了发送消息之外的流程都已经走完,剩下的就是如何通过handler把消息发送到消息队列里面去了。
- Message
public final class Message implements Parcelable {
//Message复用池最多缓存50个
private static final int MAX_POOL_SIZE = 50;
// Message内部维护了1个Message池,用于Message消息对象的复用
// 使用obtain()则是直接从池内获取
public static Message obtain() {
synchronized (sPoolSync) {
//判段有没有回收的message
if (sPool != null) {
Message m = sPool;
//链表取出
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
// 建议:使用obtain()”创建“消息对象,避免每次都使用new重新分配内存
}
// 若池内无消息对象可复用,则还是用关键字new创建
return new Message();
}
}
- Handler
//创建handler方式有两种,一个是匿名内部类,一个是构造方法,两者有什么区别,怎么选择?
private val handler = Handler(Handler.Callback {
false
})
private val handler1 =object :Handler(){
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
}
}
public class Handler {
public Handler() {
this(null, false);
}
public Handler(@Nullable Callback callback, boolean async) {
...//仅贴关键代码
//获取ThreadLocal线程中的Looper对象
mLooper = Looper.myLooper();
//如果子线程未调用Looper.prepare()则抛异常
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//绑定消息队列对象(MessageQueue)
mQueue = mLooper.mQueue;
//将构造方法的callback绑定到mCallback
//下面分发消息判断会用到
mCallback = callback;
}
//构造方法的接口Callback
public interface Callback {
boolean handleMessage(@NonNull Message msg);
}
// 注:该方法 = 空方法,在创建Handler实例时复写 = 自定义消息处理方式
public void handleMessage(@NonNull Message msg) {
}
//最终会被looper.loop 调用 msg.target.dispatchMessage(msg)回调到这方法
//派发消息到对应的Handler实例 & 根据传入的msg作出对应的操作
public void dispatchMessage(@NonNull Message msg) {
// 1. 若msg.callback属性不为空,则代表使用了post(Runnable r)发送消息
// 则执行handleCallback(msg),即回调Runnable对象里复写的run()
// 上述结论会在讲解使用“post(Runnable r)”方式时讲解
if (msg.callback != null) {
handleCallback(msg);
} else {
//判断msg.callback属性是否为空
if (mCallback != null) {
//若msg.callback属性不为空,则调用构造方法中的匿名内部类
if (mCallback.handleMessage(msg)) {
return;
}
}
// 2. 若msg.callback属性为空,则代表使用了sendMessage(Message msg)发送消息(即此处需讨论的)
// 则执行handleMessage(msg),即回调复写的handleMessage(msg)
handleMessage(msg);
}
}
//结论:两个种创建handler方法最终都会调用到handleMessage。
//先判断构造方法接口模式,当没有实现接口方式才会去调用重写方式,官方是推荐使用接口模式的。
// --------------------------------------------- 发送消息------------------------------------------------------
//发送消息 sendMessage()最终会调用到此方法
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
//设置消息时间最少为当前时间
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
//设置发送时间的消息
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
//构造方法通过mLooper.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);
}
//所有发送消息的方法最终都会调此方法把消息存入消息队列中
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
// 1. 将msg.target赋值为this
// 即 :把 当前的Handler实例对象作为msg的target属性
// 请回忆起上面说的Looper的loop()中消息循环时,会从消息队列中取出每个消息msg,然后执行msg.target.dispatchMessage(msg)去处理消息
// 实际上则是将该消息派发给对应的Handler实例
msg.target = this;
// 2. 调用消息队列的enqueueMessage()
// 即:Handler发送的消息,最终是保存到消息队列,详情看上面MessageQueue中的enqueueMessage分析
return queue.enqueueMessage(msg, uptimeMillis);
}
}
总结:
创建handler
并实现构造方法Callback
接口,在子线程中调用handler.sendMessage()
,最终调用到queue.enqueueMessage
中根据时间排序,把消息Message
存入消息队列MessageQueue
中,然后等待Looper.loop()
中queue.next()
取出消息,通过Message
中的target
就是实例化handler
调用构造方法Callback
的handleMessage
方法完成消息传递。
网友评论