一、写在前面
在Android中Handler首要被用于线程间切换,比方在子线程中拜访网络数据之后需求将数据更新到View中则需求使用到Handler进行数据处理。
1、涉及到的类
本篇文章会对如下几个类所涉及到的要害函数进行解析,以对Handler底层完成原理进行学习。
- ActivityThread.java:当时使用进程发动的时分会调用到该类的main函数,在该函数中会创立UI线程的Looper目标并调用其loop函数以发动无限循环避免进程退出;
- Looper.java:死循环调用MessageQueue中的next函数;
- MessageQueue.java:Message入行列、出行列处理类,Looper中无限循环调用被堵塞就发生在该类的next函数中;
- Handler.java:本篇文章主角类。
2、Handler简单使用
如下以在UI线程中创立Handler为例,对Handler的使用进行简单的学习。
2.1 Handler定义
static class MyHandler extends Handler {
@Override
public void handleMessage(@NonNull Message msg) {
......
//事务逻辑,当时逻辑处理则发生在UI线程中
}
}
2.2 Handler使用
//以UI线程Looper目标创立Handler,假如在子线程使用Handler则可以先创立HandlerThread目标然后经过HandlerThread目标获取Looper目标
Handler handler = new MyHandler();
Message message = handler.obtainMessage();
message.what = 1;
message.obj = new Object();
//该函数调用则可以发生在子线程中
handler.sendMessage(message);
二、源码
如下以ActivityThread->Looper->MessageQueue->Handler的次序对其间所涉及到的要害源码进行解析,当然有需求的也可以逆序看。
1、ActivityThread.main
该函数作为当时使用进程的进口函数(参阅Android使用进程发动源码),其首先经过调用Looper.prepareMainLooper
函数为当时进程的UI线程创立Looper目标,最后经过调用Looper.loop
函数以避免进程无任务处理而退出,同时等候Handler发送Message进行处理。部分源码如下:
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
......
//为当时进程UI线程创立Looper目标
Looper.prepareMainLooper();
......
//避免进程死亡,同时等候Handler发送Message进行处理
Looper.loop();
//loop意外退出,一般情况下不会出现
throw new RuntimeException("Main thread loop unexpectedly exited");
}
2、Looper
2.1 preparexx
经过调用如下函数中的其间一个则可以为当时线程成功创立Looper目标,并将创立好的Looper目标保存到ThreadLocal目标中。
ThreadLocal:线程内部数据存储类。经过该类可以在指定的线程中存储数据,并只能在存储了对应数据的线程中才能正确获取到对应数据,其他线程则无法获取到该数据。
public static void prepareMainLooper() {
//调用prepare函数创立Looper目标并保存到ThreadLocal目标中
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
//从ThreadLocal目标获取Looper目标
sMainLooper = myLooper();
}
}
public static void prepare() {
prepare(true);
}
//quitAllowed:表明是否答应退出当时Looper,关于UI线程中的Looper而言则不答应退出
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//创立Looper目标并保存到ThreadLocal目标中
sThreadLocal.set(new Looper(quitAllowed));
}
2.2 结构函数
private Looper(boolean quitAllowed) {
//创立MessageQueue目标给Handler使用
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
2.3 myLooper
//获取当时线程对应的Looper目标
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
2.4 loop
当时线程(比方UI线程)经过调用该函数以避免进程退出。代码比较简单,中心便是经过for发动无限循环并调用函数loopOnce。
public static void loop() {
//获取当时线程Looper目标
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
......
me.mSlowDeliveryDetected = false;
//死循环不断调用loopOnce函数
for (;;) {
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
2.5 loopOnce
如下代码省略掉了大部分不相关的函数完成。中心逻辑便是调用到函数MessageQueue.next
(该函数会堵塞当时线程)以获取下一个可以处理的Meesage,并最终调用到Handler中进行事务逻辑处理。留意该处调用是发生在创立Looper目标的线程中(比方UI线程),这也是可以完成线程切换的重点。
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next();
//假如没有Message需求处理而且没有被堵塞,则阐明上层事务方自动调用了quit函数而且当时looper可以退出
//则完毕当时Looper
if (msg == null) {
return false;
}
......
try {
//target对应Message的Handler目标,最终会调用到handleMessage函数
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
......
return true;
}
3、MessageQueue
3.1 next
如下代码做了如下几件事情:(1)判别当时MessageQueue是否为空,假如为空则设置下次等候时刻为-1,即永久等候直到被唤醒停止;(2)假如不为空则判别行列首部Message是否抵达了处理时刻,假如到了则立马回来进行处理,不然计算等候时刻间隔,从头等候。
Message next() {
final long ptr = mPtr;
//判别是否初始化成功
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1;
//堵塞时刻,这儿有三个值
//(1)0:不堵塞
//(2)-1:堵塞,直到被唤醒停止
//(3)>0:堵塞特定时刻之后自动唤醒
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//首次进来则不堵塞
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
//获取当时Message行列
Message msg = mMessages;
//一般情况下msg.target不会为空,因而这儿暂时不看
if (msg != null && msg.target == null) {
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
//判别当时时刻是否小于行列首部Message时刻,假如小于则阐明不存在Message需求处理
//留意Message行列首部时刻最小,越往后时刻越晚
if (now < msg.when) {
//获取最近需求处理Message时刻间隔当时时刻间隔,以计算下次需求等候时刻
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
//存在Message抵达处理时刻
} else {
mBlocked = false;
//目前剖析情况下prevMsg为Null
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
//移除即将被处理的行列头部Message
mMessages = msg.next;
}
msg.next = null;
//设置当时Message正在被处理flag
msg.markInUse();
//回来行列首部Message进行处理
return msg;
}
//Message行列为空,因而将等候时刻设置为-1(即永久等候直到被唤醒停止)
} else {
nextPollTimeoutMillis = -1;
}
if (mQuitting) {
dispose();
return null;
}
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
//阐明需求其他地方来进行唤醒,比方首个Message进入行列的时分
mBlocked = true;
continue;
}
......
nextPollTimeoutMillis = 0;
}
}
3.3 enqueueMessage
如下代码首要便是按照时刻先后次序将当时Message刺进到MessageQueue的指定节点处。MessageQueue中的节点Message对应处理时刻是头部->尾部依次递增的。
boolean enqueueMessage(Message msg, long when) {
//不答应Message对应Handler目标为null
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
synchronized (this) {
//当时Message正在被处理或许正在入行列,在上述next函数中有相关标记代码
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
//当时Looper正在退出
if (mQuitting) {
IllegalStateException e = new IllegalStateException(
msg.target + " sending message to a Handler on a dead thread");
Log.w(TAG, e.getMessage(), e);
msg.recycle();
return false;
}
//表明当时Message正在入行列
msg.markInUse();
//Message处理时刻,用于后续入行列以及设置等候时刻
msg.when = when;
//当时Message行列
Message p = mMessages;
//是否需求自动唤醒next函数中的堵塞
boolean needWake;
//阐明当时Message是第一条Message,因而需求自动唤醒
if (p == null || when == 0 || when < p.when) {
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//p.target一般不会为null,因而这儿为false
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
for (;;) {
//需求刺进节点的前一个节点
prev = p;
//需求刺进到哪个节点之前
p = p.next;
//成功找到需求刺进到哪个节点之前或许到了行列尾部
if (p == null || when < p.when) {
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
//刺进到行列中
msg.next = p;
prev.next = msg;
}
//判别是否自动唤醒next函数中的堵塞,第一次进来一般都需求自动唤醒
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
4、Handler
4.1 enqueueMessage
Handler中有多个函数都可以将Message刺进到MessageQueue中,不过最终都会调用到enqueueMessage函数中。代码如下:
/**
* queue:从当时线程Looper目标中获取
* msg:需求入行列的Message目标
* uptimeMillis:Message处理时刻,SystemClock.uptimeMillis() + 延迟时刻,或许事务方传递
*/
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
//当时Handler目标
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
//默以为false
if (mAsynchronous) {
msg.setAsynchronous(true);
}
//将Message加入到MessageQueue中
return queue.enqueueMessage(msg, uptimeMillis);
}
4.2 dispatchMessage
如下代码便是Looper.loopOnce
最终调用到的代码了。其首先会判别处理的Message目标和当时Handler目标是否存在CallBack,假如存在则优先调用CallBack目标,不然调用到当时Handler的handleMessage函数。
public void dispatchMessage(@NonNull Message msg) {
//判别Message是否设置了CallBack,经过调用Handler中的postxx函数进行设置。
if (msg.callback != null) {
handleCallback(msg);
} else {
//判别当时Handler是否设置了CallBack(可经过Handler结构函数传入,hook ActivityThread中Handler目标重点)
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//假如Message和Handler都没有设置CallBack则调用到handleMessage,后续就走到了咱们的事务逻辑。
handleMessage(msg);
}
}
三、总结
如上即为Handler底层大致源码了,其可以完成线程间切换的首要原理便是创立Looper目标的线程(比方UI线程)会不断循环(假如没有Message获取Message处理时刻未到则会被堵塞)读取MessageQueue中是否有需求处理的Message,假如有则将需求处理的Message发送给Handler进行处理;而其他子线程则只需求经过对应的Handler目标将需求处理的Message刺进到MessageQueue即可。
总之一句话,Handler中处理的事务逻辑最终运行在哪个线程中,取决于创立Handler时传递进去的Looper目标在哪个线程中被创立成功之后调用其loop函数。