1 作用
A:Android 不允许子线程操作 UI,只允许主线程操作 UI,因此通过 Handler 来实现子线程通知主主线程更新UI;
B:Handler 的出现解决了主线程与子线程的通信问题;
【关于为什么说 Android 不允许子线程操作 UI 的简要解释:
在 Android 视图的管理基类 ViewRootImpl.java 中,对于视图的计算、绘制等操作之前,都会进行 checkThread() 线程检查,如果当前操作线程不是主线程,那么会抛出异常中断当前操作,表示如下,
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
值得一提的是,ViewRootImpl.java 类是在 Activity 的 onResume 方法回调之后才创建的,那么也就是说在 APP 显示出来时,系统就已经对于主线程绘制 UI 有了判断;在 onResume 方法之前,如果用线程去创建一个 UI 组件,是不会有异常,当然,这种行为并不常用。
】
2 概念
2.1 主线程
当应用启动时,系统的 AMS 服务会告诉 Zygote 进程,Zygote 进程会 fork 一个新进程作为应用进程。这里的主线程也就指的是应用进程。
2.2 子线程
在应用中,很多耗时工作不会在主线程中完成,像是数据下载、网络请求等,那么会选择使用线程的方式,在子线程中去完成此类操作。
2.3 Message(消息)
Android 定义的在线程间通信的数据格式,主线程与子线程之间的通信,是通过封装 Message 消息,然后传递实现的。它相当于是线程间通信的数据格式封装类。
2.4 MessageQueue(消息队列)
Android 中定义的存储消息的数据结构,存取方式是 先进先出,消息队列在主线程中维护,存储 Handler 发过来的消息。消息队列中实际上是维护一个 单向链表 数据结构去管理消息的。
2.5 Handler(处理者)
Android 中定义 Handler 是作为主线程与子线程之间的通信媒介,是消息的主要处理者,主要包括两方面:
A:消息发送,将 Message 消息发送到主线程的 MessageQueue 中
B:消息接收,处理主线程 Looper 发送过来的 Message 消息
2.6 Looper(循环器)
Android 中定义 Looper 是作为循环读取 MessageQueue 的通信媒介,是消息的主要分发者,主要包括两方面:
A:消息获取,循环读取 MessageQueue 中的 Message 消息
B:消息分发,将从 MessageQueue 中读出的每一条消息分发给对应的 Handler 处理者
2.7 线程、Handler、Looper对应关系
一个线程只能对应一个 Looper
一个 Looper 可以对应多个 Handler
一个 Handler 只能对应一个 Looper
3 工作原理
3.1 工作流程
步骤一 线程间通信准备
内容:主线程创建 Looper,并开启 MessageQueue 消息循环
序列图:
详细流程:前面提到 APP 启动时,系统 AMS 会通过 Socket 告诉系统的 Zygote 进程,Zygote 进程会 fork 出一个新的进程作为 APP 主进程(这一部分涉及到应用启动逻辑,这里不展开详述,仅介绍 Handler 相关部分~)。在这个过程中,应用进程会调用 ActivityThread 类的 main() 方法,在这个方法中实现的就是 线程间通信的准备工作——创建了 Looper,并开启了 消息循环。
下面引用一张图来描述这个过程,(大家对这个流程有兴趣可以点击链接可跳跃到引用处~)
引用图片
ActivityThread.main()
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// Install selective syscall interception
AndroidOs.install();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
// 创建 Looper 对象
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 创建 MessageQueue,开启 Looper 循环执行消息读取,消息分发
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
Looper 类
这里我们又需要回到 Looper 类中去继续分析,步骤一提到 应用在启动的过程中,ActivityThread 类会去创建本进程的 Looper 和 MessageQueue。按照步骤一的流程,我们去整理下 Looper 类所用到的关键方法和变量。
public final class Looper {
// sThreadLocal.get() will return null unless you've called prepare().
@UnsupportedAppUsage
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
@UnsupportedAppUsage
private static Looper sMainLooper; // guarded by Looper.class
@UnsupportedAppUsage
final MessageQueue mQueue;
final Thread mThread;
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. The main looper for your application
* is created by the Android environment, so you should never need
* to call this function yourself. See also: {@link #prepare()}
*/
// 这里是 ActivityThread 类调用方法,为创建主线程 Looper 而封装的。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
// 创建 Looper 对象,此方法并没有返回 Looper 对象,而是保存到 ThreadLocal 对象中。
private static void prepare(boolean quitAllowed) {
// 注意,这里就是确保一个线程只能对应初始化一次Looper的代码位置
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
// 实例化 Looper 对象,并且加入到 ThreadLocal 对象中保存
sThreadLocal.set(new Looper(quitAllowed));
}
// Looper 私有构造函数,创建 Looper 对象对应的 MessageQueue,并且记录当前线程
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
// 获取 Looper 对象,是从 ThreadLocal 中获取,之前提到 Looper 对象没有返回,是保存到 ThreadLocal 对象中去,这里获取 Looper 对象,也是从 ThreadLocal 对象中去拿。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
从上面的 Looper 实例化的过程中,我们发现,能够确保线程拿到的 Looper 对象是本线程创建的关键在于 ThreadLocal 类中。
ThreadLocal 类型变量叫做线程变量,表示 ThreadLocal 中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程的独有变量。其原理就是基于线程维护一个 ThreadLocalMap 数据结构,数据以 Key - Value 的对应格式保存,Key 为 ThreadLocal 类,对应的 Value 是我们传入的数据。在获取的时候,会先根据线程去获取线程对应的 ThreadLocalMap 类,然后从 ThreadLocalMap 类中根据 ThreadLocal 获取数据。
步骤二:消息按序入队
内容:子线程创建 Handler 对象,并构建 Message 消息通过 Handler 对象发送给主线程
实现方式:Handler 提供两种方式去发送消息,sendMessage() 和 post();这两种方式都有不同的方式去处理消息,sendMessage() 方式是通过重写 handleMessage() 方法去完成消息的接收处理;post() 方式是通过传入一个 Runnable 对象,实现其 run() 方法,在 run() 方法中完成消息的接受处理。在分析具体的实现方式之前,还有一些疑点需要先分析。
分析一 Handler 与 Looper 的绑定
前文有提到,子线程使用 Handler 时,要绑定主线程的 Looper & MessageQueue,这一块的实现,Handler 的构造函数帮我们完成了,如下:
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
// 此 Handler 构造函数是常用的构造函数,它调用的是重载方法执行创建。
public Handler() {
this(null, false);
}
/**
* Use the {@link Looper} for the current thread with the specified callback interface
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
// 创建 Handler 对象。
// 参数分析:参数一 Callback 对象,见 Callback 分析;参数二 async 标识 Message 消息是否 异步
public Handler(@Nullable Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
// 这里 Looper.myLooper() 就是去获取了本线程的 Looper 对象。每个线程都对应一个 Looper 对象。
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// 这里通过主线程的 Looper 对象,也就拿到了 主进程的 MessageQueue,那么后续的消息发送,其实就是往这个 Queue 里写入数据,完成 Message 消息的按序发送。
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
// Callback 分析:
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
*/
// Callback 接口,创建者需要实现 handleMessage() 方法去完成消息的接收处理。创建者提供一个 Callback 对象,跟重写 handleMessage() 的方式如出一辙
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
boolean handleMessage(@NonNull Message msg);
}
这里出现一个问题,多个应用进程会有多个 Looper 对象,那么子线程通过 Looper.myLooper() 去获取 Looper 对象的时候,如何确定拿到的就是对应主线程的 Looper 对象。解答:这里是我对于 线程 与 Looper 对应的一个误区,我原本理解认为每个进程都会创建一个 Looper,进程下的线程在创建 Handler 时是共享这个 Looper,Handler 会自动关联到 Looper 对象,关联到主进程的 MessageQueue,基于这个理解才引出子线程创建Handler时,是怎么区分是本进程的 Looper。实际上,每一个线程都对应一个 Looper 对象,如果你使用主线程的全局 Handler,那么由于这个 Handler 是主进程创建的,也就自然绑定主进程的 Looper 对象,这是一种实现;如果你使用的是子线程自定义的 Handler 对象,那么在使用默认 Handler 构造函数的情况下,Handler 对象是绑定自己线程的 Looper 对象,也就是说默认的子线程的 Handler 并没有绑定主线程的 Looper,这种情况下,就要先去获取主进程的 Looper,在通过 Handler 带参构造函数,把 Looper 对象传进去创建 Handler 以实现主进程 Looper 绑定。
A:主线程创建 Handler,此 Handler 绑定了主线程的 Looper & MessageQueue,其他子线程使用此 Handler 处理消息。
B:子线程通过 Looper.getMainLooper() 获取主线程的 Looper 对象,通过 Handler(MainLooper) 创建 Handler,绑定主线程的 Looper & MessageQueue。
实现方式一:Handler.sendMessage(Message msg)
A:新建 Handler 子类或者是匿名内部类,内部重写 handleMessage(Message msg) 函数,添加消息处理逻辑;
B:主线程创建 Handler 对象;
C:子线程创建 Message 消息;
D:子线程调用主线程创建的 handler 对象的 sendMessage(Message msg) 函数将消息发送到主线程的 MessageQueue 中去;
子线程创建 Message 消息:Message 类的创建一般使用静态方法 obtain() 及其多个重载函数。我们来看一下 Message 的结构,是如何描述一条消息的。
上面是 Message 类的类图,下面简要描述:
what:消息标识;接收方可以通过此标识区分消息
arg1:存储 int 类型值;
arg2:存储 int 类型值;
obj:存储任意数据 Object 类型消息对象;
target:Handler 对象,标记在主线程循环过程中,会将此消息发送给这里的 Handler 对象,进行消息处理。此 target 指向的是 发送此 Message 消息的 Handler 对象;
callback:Runnable 对象,如果有值,可能是采用 post 方式发送的,在处理消息的时候,会调用此 Runnable 对象的 run() 方法执行消息处理逻辑;
源码分析:
Message类:
构造 Message 消息的逻辑:
/**
* 源码分析 Message.obtain()
* 作用:创建 Message 消息对象
* obtain()封装原因:在创建消息对象时,仍然可以使用 new Message() 的方式创建,但是直接 new 的方式 * 会直接分配内存;而 Message 类内部维护了一个 Message 池,obtain()方法会先去 Message 池中寻找
* 是否有可复用的 Message 对象,没有复用则再去新建,避免直接新建而浪费内存。
*/
public static Message obtain() {
// 这里则是在 Message 池中寻找是否有复用的 Message 对象,obtain() 从池中获取
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
// 若 Message 池内没有对象可以复用,则还是用 new 的方式创建
return new Message();
}
Handler类
sendMessage() 处理逻辑:
/**
* 源码分析:sendMessage(Message msg)
* 入参:Message 对象
* 逻辑:调用 sendMessageDelayed()继续执行
*/
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
/**
* 源码分析:sendMessageDelayed()
* 入参:Message 消息;delayMillis 延迟时间
* 功能:在 当前时间+延迟时间 之后,将消息插入到队列中
*/
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
/**
* 源码分析:sendMessageAtTime()
* 入参:Message 消息; uptimeMillis 消息插入时间
* 功能:获取消息队列,在 uptimeMillis 时间将消息插入到队列中
*/
public boolean sendMessageAtTime(@NonNull 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);
}
/**
* 源码分析:enqueueMessage()
* 入参:MessageQueue 要插入的消息队列;Message 消息;uptimeMillis 时间
* 功能:设置 Message 的 target 对象、Uid、Asynchronous;调用 MessageQueue 的 enqueueMessage() 函数将消息插入队列中
*/
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
// target 参数,这里的 target 指向发送方 Handler 对象,后续主进程在 loop 时,会根据 target 值确定发送方执行处理逻辑
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 调用消息队列的 enqueueMessage() 函数将消息插入队列
return queue.enqueueMessage(msg, uptimeMillis);
}
MessageQueue类
将消息按序插入消息队列的逻辑:
/**
* 源码分析:enqueueMessage()
* 入参:Message 消息;when 时间
* 功能:这里是具体将 Message 消息插入消息队列的逻辑
*/
boolean enqueueMessage(Message msg, long when) {
// 如果 Message 消息没有指定 target,抛异常,没有指定谁去处理消息
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
// 此处标识,此消息是否已经使用
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
synchronized (this) {
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();
// 标识消息执行的时间,队列是按照消息时间进行排序入队的
msg.when = when;
// mMessages 这里我理解是获取的消息队列中第一个消息
Message p = mMessages;
// 是否需要唤醒
boolean needWake;
if (p == null || when == 0 || when < p.when) {
/* 此条件判断处理分析
* p == null 情况代表 当前消息队列中没有消息
* when == 0 情况代表 当前消息需要立刻处理
* when < p.when 情况代表 当前消息需要在队列中第一个消息前处理
* 以上三种情况下:需要重新定义消息队列的第一个数据。
*/
// New head, wake up the event queue if blocked.
// 如果 p 为 null,标识当前的消息队列中没有消息
msg.next = p;
// 初始化头消息,传入的消息是第一个消息
mMessages = msg;
// true 表示没有消息,阻塞线程; false 表示有消息,唤醒线程
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;
// 将消息放入到队列中,消息按照 when 时间排序
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
/* 寻找 msg 消息应该处于消息队列的位置
* p == null 情况代表 已经找到最后一个位置
* when < p.when 情况代表 当前消息要在 p 消息前处理
* 以上两种情况下:则找到 msg 在消息队列中按时间顺序应处的位置
*/
break;
}
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 上述循环 break 位置,就是此条消息在消息队列中按时间顺序应处的位置
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;
}
实现方式二:Handler.post(Runnable r)
A:主线程创建 Handler 对象;
B:子线程实现一个 Runnable 对象,可以是个匿名内部类,重写 run() 方法指定消息处理逻辑;
C:子线程调用 handler 对象的 post(Runable r) 函数将消息发送到主线程的 MessageQueue 中去;
post() 实现方式值得注意的点有两点:第一点,post方法执行之前子线程并没有去创建 Message 对象,那是因为在 Handler 源码实现中,基于 Runnable 对象帮我们完成 Message 的封装;第二点,Runnable 对象并没有创建新线程,而是发送消息到消息队列中,没有调用其 start() 方法。
源码分析:
Handler类:
post() 插入消息:
/**
* 源码分析:post()
* 入参:Runnable 对象
* 功能:通过 getPostMessage(Runnable) 方法构造一个 Message,将消息发送到消息队列中,此逻辑跟
* sendMessage() 逻辑一致
*/
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
/**
* 源码分析:getPostMessage()
* 入参:Runnable 对象
* 功能:封装一个 Message 对象
*/
private static Message getPostMessage(Runnable r) {
// 通过 obtain() 方法创建一个 Message 对象
Message m = Message.obtain();
// 指定 Message 的 Callback 函数,后续在处理 Message 时,会通过 callback 对象执行消息处理逻辑
m.callback = r;
return m;
}
// 下面的逻辑跟 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;
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) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
步骤三:消息循环分发
内容:主线程循环读取 MessageQueue 中的 Message 消息,并分发
序列图:
实现方式:步骤一提到应用在启动过程中,在创建应用进程的过程中,会开启应用进程的 Looper 循环,循环读取 MessageQueue 中的消息,读取分发。
源码分析:
Looper类:
loop()函数:
/**
* 源码分析:loop() 函数
* 入参:无
* 功能:循环读取关联的 MessageQueue 队列中的 Message 消息,并分发处理
*/
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.");
}
// 获取 Looper 对象关联的 MessageQueue 对象
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
boolean slowDeliveryDetected = false;
// 开启循环读取
for (;;) {
// 从队列中读取下一条 Message 消息
Message msg = queue.next(); // might block 可能会阻塞
// 这里的 msg == null,并不是说没有消息了,而是如果在消息队列正在关闭的情况下,会返回 null;
// 如果消息队列中没有消息,上述会阻塞;
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
// Make sure the observer won't change while processing a transaction.
final Observer observer = sObserver;
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
// 分发消息,调用 Message 的 target Handler类型变量的 dispatchMessage() 方法处理消息
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);
}
}
if (logSlowDelivery) {
if (slowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
slowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery", msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
slowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
// 将 Message 添加回收标记后,放入 Message 消息池中,以便重复使用
msg.recycleUnchecked();
}
}
这里可能会出现一个问题:上述表示在主线程中 Looper.loop() 会一致循环读取 MessageQueue 中的消息,如果没有消息,在 queue.next() 方法时会阻塞,那为什么不会导致 ANR 呢?
解答:
第一点:这个答案需要去 MessageQueue 类中寻找。MessageQueue 底层采用了 epoll 机制进行阻塞,当接收到消息时会唤醒主线程,由 Looper 监控管道中的消息,每当唤醒的时候,向管道中发送唤醒的文件描述符,而在 Looper.loop() 循环获取消息的时候,会优先调用 epoll_wait 等待,然后获取等待过程中管道的文件描述符的数量,判断是否要唤醒主线程。
第二点:ANR 实际上也是一个 Message,实际上 ANR 的触发也是 Handler 机制完成的,但是这里如果 Looper 循环阻塞了,其实也就表示着线程没什么事情做了,这时候需要交出 CPU 资源,进行阻塞睡眠,再有消息来的时候,由底层来唤醒主线程,进行消息处理。
Handler类:
dispatchMessage()分析:
/**
* 源码分析:dispatchMessage()
* 入参:Message 消息
* 功能:处理消息逻辑
*/
public void dispatchMessage(@NonNull Message msg) {
// post 方式发送消息,调用 post() 函数时会传入 Runnable 对象,调用 handleCallback() 函数处理
if (msg.callback != null) {
handleCallback(msg);
} else {
// mCallback 对象是 Handler 类中自定义的 Callback 接口;内部定义方法 handleMessage() 描述了消息处理的逻辑,mCallback 的赋值时通过 Handler 初始化时传入的
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
// sendMessage 方式发送消息,调用 handleMessage() 函数处理
handleMessage(msg);
}
}
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.回调接口,可以在实例化Handler时使用,以
* 避免必须实现Handler的自己的子类。
*/
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
*/
boolean handleMessage(@NonNull Message msg);
}
Message 类:
recycleUnchecked() 函数:
/**
* Recycles a Message that may be in-use.
* Used internally by the MessageQueue and Looper when disposing of queued Messages.
* 回收消息,以便后续复用
*/
@UnsupportedAppUsage
void recycleUnchecked() {
// Mark the message as in use while it remains in the recycled object pool.
// Clear out all other details.
// 将消息保留在 Message 池中,Message 对象恢复初始状态
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
// 将此 Message 消息添加到消息池中
synchronized (sPoolSync) {
// 消息池最大容量判断
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
步骤四:消息接收处理
内容:子线程实现 Handler 消息的处理逻辑
实现方式:子线程实现消息的接受处理大概有三种方式,分别是 重写handleMessage()方法、实现Runnable接口run()方法、实现Callback接口handleMessage()方法;
实现方式一:使用 sendMessage() 方式传递消息,重写 handleMessage() 方法;
/**
* 具体使用方法
*/
private Handler mhandler = new Handler() {
// 通过重写 handleMessage() 方法完成消息的处理逻辑
@Override
public void handleMessage(Message msg) {
... // 需要执行的操作
}
}
/**
* Handle system messages here.
* Handler 处理消息分发逻辑
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
/**
* Subclasses must implement this to receive messages..
* 通过 Handler.dispatchMessage() 又会调回到此方法,此方法被应用重写
*/
public void handleMessage(@NonNull Message msg) {
}
实现方式二:使用 post() 方式传递消息,实现 Runnable 接口的 run() 方法;
/**
* 具体使用方法
*/
mhandler.post(new Runnable() {
// 传入一个 Runnable 对象,复写 run() 方法完成消息逻辑的处理
@Override
public void run() {
... // 需要实现的操作
}
});
/**
* Handle system messages here.
* Handler 处理消息分发逻辑
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
// 通过 Handle 的 dispatchMessage() 方法分发,会调用到 Runnable 对象的 run() 方法
private static void handleCallback(Message message) {
message.callback.run();
}
实现方式三:实现 Callback 接口 handleMessage() 方法
/**
* 具体使用方法
*/
public class TestCallback implement Callback {
@Ovierride
boolean handleMessage(Message msg) {
... // 消息处理逻辑
}
}
TestCallback testCallback = new TestCallback();
// 新建 Handler 对象,传入创建的 testCallback 对象
private Handler mhandler = new Handler(testCallback);
/**
* Handle system messages here.
* Handler 处理消息分发逻辑
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
/**
* Callback interface you can use when instantiating a Handler to avoid
* having to implement your own subclass of Handler.
* Handler 类内部的 Callback 接口的定义
*/
public interface Callback {
/**
* @param msg A {@link android.os.Message Message} object
* @return True if no further handling is desired
* 消息会通过 Handler 的 dispatchMessage() 方法分发到这里,handleMessage() 实现
*/
boolean handleMessage(@NonNull Message msg);
}
4 Demo示例
4.1 子线程中处理 UI 更新报错
/**
* 子线程中进行 UI 操作
*/
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
button = view.findViewById(R.id.button_first);
view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread("Thread_1") {
@Override
public void run() {
Log.d(TAG, "Thread is " + this.getName());
// 在子线程中设置 UI
button.setText("onclick1");
button.refreshDrawableState();
}
}.start();
}
});
}
操作结果:会出现异常,只有创建 UI 的线程才能进行 UI 操作。
D/HandlerTest: Thread is Thread_1
E/AndroidRuntime: FATAL EXCEPTION: Thread_1
Process: com.example.handlertest, PID: 9705
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:8372)
at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1444)
at android.view.View.requestLayout(View.java:25010)
at android.view.View.requestLayout(View.java:25010)
at android.view.View.requestLayout(View.java:25010)
at android.view.View.requestLayout(View.java:25010)
at android.view.View.requestLayout(View.java:25010)
at android.view.View.requestLayout(View.java:25010)
at android.view.View.requestLayout(View.java:25010)
at androidx.constraintlayout.widget.ConstraintLayout.requestLayout(ConstraintLayout.java:3172)
at android.view.View.requestLayout(View.java:25010)
at android.view.View.requestLayout(View.java:25010)
at androidx.constraintlayout.widget.ConstraintLayout.requestLayout(ConstraintLayout.java:3172)
at android.view.View.requestLayout(View.java:25010)
at android.widget.TextView.checkForRelayout(TextView.java:9686)
at android.widget.TextView.setText(TextView.java:6274)
at android.widget.TextView.setText(TextView.java:6102)
at android.widget.TextView.setText(TextView.java:6054)
at com.example.handlertest.FirstFragment$1$1.run(FirstFragment.java:43)
4.2 sendMessage() 方式
/**
* 方式一:
* 主线程中创建 Handler,子线程使用 Handler 发送消息进行 UI 操作
*/
public Handler handler1 = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
Log.d(TAG, "Thread is " + Thread.currentThread().getName());
button.setText("onclick1");
button.refreshDrawableState();
}
};
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread("Thread_2") {
@Override
public void run() {
Log.d(TAG, "Thread is " + this.getName());
Message message = Message.obtain();
message.what = 1;
handler1.sendMessage(message);
}
}.start();
}
});
}
操作结果:UI 设置成功
日志:
D/HandlerTest: Thread is Thread_2
D/HandlerTest: Thread is main
/**
* 方式二:
* 子线程中创建 Handler,绑定主线程的 Looper,重写 Handler 的 handleMessage() 方法实现 UI 的操作
*/
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread("Thread_2") {
@Override
public void run() {
Log.d(TAG, "Thread is " + this.getName());
Looper loop = Looper.getMainLooper();
Handler handler = new Handler(loop) {
@Override
public void handleMessage(@NonNull Message msg) {
Log.d(TAG, "Thread is " + Thread.currentThread().getName());
button.setText("onclick1");
button.refreshDrawableState();
}
};
Message message = Message.obtain();
message.what = 1;
handler.sendMessage(message);
}
}.start();
}
});
}
操作结果:UI 设置成功
日志:
D/HandlerTest: Thread is Thread_2
D/HandlerTest: Thread is main
操作截图:
4.3 post() 方式
/**
* 方式一:
* 主线程中创建 Handler 对象,调用 handler.post() 传递信息
*/
public Handler handler2 = new Handler();
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread("Thread_3") {
@Override
public void run() {
Log.d(TAG, "Thread is " + this.getName());
handler2.post(new Runnable() {
@Override
public void run() {
Log.d(TAG, "Thread is " + Thread.currentThread().getName());
button.setText("onclick1");
button.refreshDrawableState();
}
});
}
}.start();
}
});
}
操作结果:UI 设置成功
日志:
D/HandlerTest: Thread is Thread_3
D/HandlerTest: Thread is main
/**
* 方式二:
* 子线程中创建 Handler 对象,绑定主线程的 Looper 对象,调用 Handler.post() 传递消息
*/
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread("Thread_3") {
@Override
public void run() {
Log.d(TAG, "Thread is " + this.getName());
Looper loop = Looper.getMainLooper();
Handler handler3 = new Handler(loop);
handler3.post(new Runnable() {
@Override
public void run() {
Log.d(TAG, "Thread is " + Thread.currentThread().getName());
button.setText("onclick1");
button.refreshDrawableState();
}
});
}
}.start();
}
});
}
操作结果:UI 设置成功
日志:
D/HandlerTest: Thread is Thread_3
D/HandlerTest: Thread is main
操作截图:
4.4 实现 Handler.Callback 方式
/**
* 方式一:
* 主线程中创建 Handler,传入 Callback 接口的实现,子线程使用 handler.sendMessage() 方式传递消息
*/
// 定义带 Callback 参数的 Handler
public Handler handler3 = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
Log.d(TAG, "Thread is " + Thread.currentThread().getName());
button.setText("onclick1");
button.refreshDrawableState();
return true;
}
});
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread("Thread_4") {
@Override
public void run() {
Log.d(TAG, "Thread is " + this.getName());
Message message = Message.obtain();
handler3.sendMessage(message);
}
}.start();
}
});
}
操作结果:UI 设置成功
日志:
D/HandlerTest: Thread is Thread_4
D/HandlerTest: Thread is main
/**
* 方式二:
* 子线程创建 Handler,绑定主线程 Looper,传入 Callback 实现,调用 handler.sendMessage() 传递消息
*/
public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.findViewById(R.id.button_first).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
new Thread("Thread_4") {
@Override
public void run() {
Log.d(TAG, "Thread is " + this.getName());
Looper loop = Looper.getMainLooper();
Handler handler3 = new Handler(loop, new Handler.Callback() {
@Override
public boolean handleMessage(@NonNull Message msg) {
Log.d(TAG, "Thread is " + Thread.currentThread().getName());
button.setText("onclick1");
button.refreshDrawableState();
return true;
}
});
Message message = Message.obtain();
handler3.sendMessage(message);
}
}.start();
}
});
}
操作结果:UI 设置成功
日志:
D/HandlerTest: Thread is Thread_4
D/HandlerTest: Thread is main
操作截图:
5 总结
以上就是关于 Android Handler机制的基础知识,涉及功能类 Handler、Looper、Message、MessageQueue等,以及关于 Handler 原理及使用 Demo 示例;对于 Native 层 Handler 原理,MessageQueue 如何获取 Message、阻塞线程、唤醒线程,大家有兴趣可以再研究。
若文中有错误,请大家指出,必当有则改之。谢谢~