0. 系列文章汇总
1.关键机制说明
1.1分发机制
分发是在Looper.loop()会在for循环中不停地从Message Queue中取出消息,并调用消息对应的Handler对象的dispatchMessage方法,详细执行见源码
其对于处理Message三种方法,且有优先级:
- 当Message的回调方法不为空时,则回调方法
msg.callback.run()
,其中callBack数据类型为Runnable,否则进入步骤2; - 当Handler的mCallback成员变量不为空时,则回调方法
mCallback.handleMessage(msg)
,否则进入步骤3; - 调用Handler自身的回调方法
handleMessage()
,该方法默认为空,Handler子类通过覆写该方法来完成具体的逻辑。
/**
* 处理系统消息,在Looper.loop(),当发现有消息时,会调用消息的目标Handler,执行此方法来分发消息
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
// 当Message存在回调方法时,回调msg.callback.run()方法
handleCallback(msg);
} else {
if (mCallback != null) {
// 当Handler存在callback成员变量时,回调callback的handleMessage方法
if (mCallback.handleMessage(msg)) {
return;
}
}
// 执行Handler自身的回调方法handleMessage
handleMessage(msg);
}
}
1.2 消息发送机制
在Handler 有各种类型的发送消息的机制,有实时发送(例如:sendMessage(@NonNull Message msg
),延时相对时间发送(sendMessageDelayed(@NonNull Message msg, long delayMillis)
),指定绝对时间发送(sendMessageAtTime(@NonNull Message msg, long uptimeMillis)
)等,但是实际上最终调用queue.enqueueMessage
方法
需要重点注意的时间,延时是通过SystemClock.uptimeMillis() 加上延时时间来计算的。SystemClock 有一个特点是在手机休眠时间是不计时的,所以在后台执行时有可能会实际执行比指定延时时间delayMillis
更长。
2. 问题
- Q: Handler 、MessageQueue、Looper和线程分别是什么关系?
A: 一个线程只有一个Looper,通过ThreadLocal
实现,且也只对应一个MessageQueue,但是可以有多个Handler。Message对象会关联一个Handler对象,message.target
,Handler也只会处理自己发送的消息。
即Handler:MessageQueue:Looper:Thread = N:1:1:1; - Q:为什么实际延迟消息处理时间比指定时间更长。
A:有两个原因,一个延迟处理是通过SystemClock.uptimeMillis() 来计算的,此方法在系统休眠时并不会计时。还有一个原因是队列中的消息是要逐个处理的,当消息队列中消息过多时也造成延时。 - Q:HandlerMessage的使用场景及禁止使用的场景
在Android系统中出于性能优化考虑,Android的UI操作并不是线程安全的,这意味着如果有多个线程并发操作UI组件,可能导致线程安全问题。为了解决这个问题,Android制定了一条简单的原则,只允许UI线程(亦即主线程)修改Activity中的UI组件,否则会抛出异常,但是我们经常将耗时操作(DB、网络在子线程进行操作),这也就需要通过HandlerMessage机制将消息从子线程切换到主线程。总结就是:在子线程做完耗时的逻辑处理后 将消息或者结果发送到主线程用于更新UI,其他场景都不建议大家使用HandlerMessage机制。
禁止的场景是:子线程发送Message消息对象到主线程处理,又将消息对象因为耗时或者其他原因切换子线程来进行处理。这种会导致多线程安全问题。因为我们现在建议的方法都是通过obtainMessage
从消息池获取,在Looper.loop()方法中,方法处理方法dispatchMessage
和消息回收方法msg.recycleUnchecked()
,也就是说如果你在dispatchMessage方法中将Message对象传递到子线程处理时,Message对象有可能被回收了,导致多线程安全问题。
3.源码
源码我将部分dump 和日志打印删节后全部贴上来,用于备查
package android.os;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.util.Log;
import android.util.Printer;
import java.lang.reflect.Modifier;
/**
* Handler可以发送和处理{@link Message}对象,以及与线程的{@link MessageQueue} 关联的Runnable对象,
* 每一个Hnadler 对象只能关联一个线程以及这个线程对应的Looper。当创建一个新的Handler,它将绑定到{@link Looper}。
* Hanlder会将消息和Runnable对象传递到Looper中的消息队列,并且在Looper关联的线程中执行他们。
* 即可以理解,Handler:Looper:Thread:MessageQueue=N:1:1:1
*
* Hnadler 有两个主要用途:1)调度Message和Runnable实现类对象在未来的某个时间点来执行。
* 2)将耗时任务安排在其他线程执行而不是当前线程
*
* 当post或者send消息到Handler时,用户可以让消息当消息队列Ready后立马处理,也可以延迟指定时间或者绝对时间再处理。
* 后面两次方法可以实现超时、或者其他基于计时的行为。
*
* 当应用的进程被创建后,主线程专用于一个Message queue,负责管理顶级应用对象(activities, broadcast receivers, etc)
* 和创建的窗口。用户可以创建自己的子线程,然后通过Handler和主线程进行通信,实现方法是在子线程中调用post 或者sendMessage等方法,
* 被传入的Runnable实现类对象和Message对象会被排入Handler中的Message Queue,然后在适当的时候进行处理
*/
public class Handler {
@UnsupportedAppUsage
final Looper mLooper;
final MessageQueue mQueue;
@UnsupportedAppUsage
final Callback mCallback;
final boolean mAsynchronous;
@UnsupportedAppUsage
IMessenger mMessenger;
/*
* 当此标志设备为true,以检测非静态的匿名内部类(继承于Handler),这种类可能会产生内存泄漏
*/
private static final boolean FIND_POTENTIAL_LEAKS = false;
private static final String TAG = "Handler";
private static Handler MAIN_THREAD_HANDLER = null;
/**
* 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
*/
boolean handleMessage(@NonNull Message msg);
}
/**
* 子类必须实现他用于接收消息
*/
public void handleMessage(@NonNull Message msg) {
}
/**
* 处理系统消息,在Looper.loop(),当发现有消息时,会调用消息的目标Handler,执行此方法来分发消息
*/
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
// 当Message存在回调方法时,回调msg.callback.run()方法
handleCallback(msg);
} else {
if (mCallback != null) {
// 当Handler存在callback成员变量时,回调callback的handleMessage方法
if (mCallback.handleMessage(msg)) {
return;
}
}
// 执行Handler自身的回调方法handleMessage
handleMessage(msg);
}
}
/**
* 默认构建方法,将当前线程的{@link Looper} 与此Handler对象进行关联
*
* 如果当前线程没有Looper,此Handler没有办法去接收消息,所以会抛出Exception
*
* @deprecated 在构建Handler时隐式指定Looper会导致一些错误,当Handler关联的线程不是用户想要的。比如:operations丢失(如果Hnadler没有接收新任务并退出),
* Crashes(如果Handler不小心在构建时关联了一个没有Active Looper对象的线程),或者race Condition
* 相反地,使用{@link java.util.concurrent.Executor},或者通过
* {@link Looper#getMainLooper}, {link android.view.View#getHandler}或者类似的方法 显式指定Looper,
* 为了兼容当前线程的隐式构建方法,使用{@code new Handler(Looper.myLooper())}
*
*/
@Deprecated
public Handler() {
this(null, false);
}
/**
* Constructor associates this handler with the {@link Looper} for the
* current thread and takes a callback interface in which you can handle
* messages.
* 构造方法将Handler 与当前线程的Looper进行关联,并指定一个可以处理消息的callback接口
*
* @param callback 用于处理消息的Callback接口,也可以为空
**/
@Deprecated
public Handler(@Nullable Callback callback) {
this(callback, false);
}
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
this(looper, callback, false);
}
@UnsupportedAppUsage
public Handler(boolean async) {
this(null, async);
}
/**
* 指定Looper为当前线程的Looper且为设置此Handler是否为异步,以及指定一个处理消息Callback接口
*
* 默认情况下,Handler是同步的,除非使用该构造函数指定为异步的
*
* 异步消息表示不需要相对于同步消息进行全局排序的中断或事件。
* 异步消息不受{@link MessageQueue#enqueueSyncBarrier(long)引入的同步barriers的影响。
*
* @param callback 用于处理消息的callback接口实现类,也可为空
* @param async 如果为true,则handler会
* 对于每一个他分发的Message对象或者Runnable实现类都调用调用{@link Message#setAsynchronous(boolean)}
*
* @hide
*/
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());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
// 也即意味着在调用Handler方法前,必要调用先调用Looper.prepare()
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
/**
*
* @param looper The looper, 不允许为空
* @param callback 用于处理消息的callback接口实现类,也可为空
* @param async 如果为true,则handler会
* 对于每一个他分发的Message对象或者Runnable实现类都调用调用{@link Message#setAsynchronous(boolean)}
*
* @hide
*/
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
@NonNull
public static Handler createAsync(@NonNull Looper looper) {
if (looper == null) throw new NullPointerException("looper must not be null");
return new Handler(looper, null, true);
}
/**
* 创建一个新的Handler,posted 的消息和Runnables对象不受同步barriers的约束,例如display vsync
*
* <p>Messages sent to an async handler are guaranteed to be ordered with respect to one another,
* but not necessarily with respect to messages from other Handlers.</p>
*
* @see #createAsync(Looper) to create an async Handler without custom message handling.
*
* @param looper the Looper that the new Handler should be bound to
* @return a new async Handler instance
*/
@NonNull
public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {
if (looper == null) throw new NullPointerException("looper must not be null");
if (callback == null) throw new NullPointerException("callback must not be null");
return new Handler(looper, callback, true);
}
/** @hide */
@UnsupportedAppUsage
@NonNull
public static Handler getMain() {
if (MAIN_THREAD_HANDLER == null) {
MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper());
}
return MAIN_THREAD_HANDLER;
}
/** @hide */
@NonNull
public static Handler mainIfNull(@Nullable Handler handler) {
return handler == null ? getMain() : handler;
}
/**
* 返回一个表示指定消息名称的字符串。默认实现要么返回* message回调的类名(如果有的话),要么返回* message“what”字段的十六进制表示。
*
* @param message 需要查询名称的消息对象
*/
@NonNull
public String getMessageName(@NonNull Message message) {
if (message.callback != null) {
return message.callback.getClass().getName();
}
return "0x" + Integer.toHexString(message.what);
}
/**
* 从消息池中返回一个新的Message对象 {@link android.os.Message Message} .
* 创建的消息会将此Handler设置为此实例(Message.target == this).
* 也可以通过Message.obtain()来代替
*/
@NonNull
public final Message obtainMessage()
{
return Message.obtain(this);
}
@NonNull
public final Message obtainMessage(int what)
{
return Message.obtain(this, what);
}
@NonNull
public final Message obtainMessage(int what, @Nullable Object obj) {
return Message.obtain(this, what, obj);
}
@NonNull
public final Message obtainMessage(int what, int arg1, int arg2)
{
return Message.obtain(this, what, arg1, arg2);
}
@NonNull
public final Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
return Message.obtain(this, what, arg1, arg2, obj);
}
/**
* 将Runnable实现类添加到消息对队中,Runnable实现类在在Handler关联的线程中执行。
*
* @param r The Runnable that will be executed.
* @return 当Runnable实现类对象r成功添加到消息队列中返回true,失败时则返回false,通常是因为处理消息队列的Looper不存在
*/
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
/**
* 将Runnable实现类添加到消息对队中,其将会在uptimeMillis指定的特定时间执行,手机休眠会增加执行的额外延迟,
* Runnable实现类在在Handler关联的线程中执行。
*
* @param r The Runnable that will be executed.
* @param uptimeMillis 回调执行的绝对时间,(并非相对时间),使用{@link android.os.SystemClock#uptimeMillis}作为基础时间
*/
public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
/**
* Causes the Runnable r to be added to the message queue, to be run
* at a specific time given by <var>uptimeMillis</var>.
* 将Runnable实现类添加到消息对队中,其将会在uptimeMillis指定的特定时间执行,手机休眠会增加执行的额外延迟,
* Runnable实现类在在Handler关联的线程中执行。
*
* @param r The Runnable that will be executed.
* @param token 可以通过此Token 通过{@link #removeCallbacksAndMessages}取消{@code r}的实例
* @param uptimeMillis 回调执行的绝对时间,(并非相对时间),使用{@link android.os.SystemClock#uptimeMillis}作为基础时间
*
* @return 当Runnable实现类对象r成功添加到消息队列中返回true,失败时则返回false,通常是因为处理消息队列的Looper不存在
* 注意:返回true并不代表Runnable会被执行,比如如果Looper被quit()在消息被分发时,会导致队列中的所有消息都被丢弃
*
* @see android.os.SystemClock#uptimeMillis
*/
public final boolean postAtTime(
@NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
/** @hide */
public final boolean postDelayed(Runnable r, int what, long delayMillis) {
return sendMessageDelayed(getPostMessage(r).setWhat(what), delayMillis);
}
public final boolean postDelayed(
@NonNull Runnable r, @Nullable Object token, long delayMillis) {
return sendMessageDelayed(getPostMessage(r, token), delayMillis);
}
/**
* 将发送一个Runnable实现类到队列队首,消息将在下一次循环时首先执行
* 此方法仅用于非常特殊的情况下使用,它会带来排序问题以及其他副作用
**/
public final boolean postAtFrontOfQueue(@NonNull Runnable r) {
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
/**
* 同步运行指定的任务(同步方法)(危险方法)
* <p>
* 如果当前线程是Handler关联线程,则Runnable会立马执行,否则会将Runnables 发送至Handlersr执行且等他执行完成
**/
public final boolean runWithScissors(@NonNull Runnable r, long timeout) {
if (r == null) {
throw new IllegalArgumentException("runnable must not be null");
}
if (timeout < 0) {
throw new IllegalArgumentException("timeout must be non-negative");
}
if (Looper.myLooper() == mLooper) {
r.run();
return true;
}
BlockingRunnable br = new BlockingRunnable(r);
return br.postAndWait(this, timeout);
}
/**
* 删除所有消息队列中待等待执行的Runnable实现类对象
*/
public final void removeCallbacks(@NonNull Runnable r) {
mQueue.removeMessages(this, r, null);
}
/**
* 删除所有带有token的等待执行的Runnable实现类对象,如果token为null,则所有的callbacks将会被删除
*/
public final void removeCallbacks(@NonNull Runnable r, @Nullable Object token) {
mQueue.removeMessages(this, r, token);
}
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what)
{
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}
/**
* 发送一个延迟delayMillis ms的消息到队列中
**/
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
/**
* 在绝对时间uptimeMillis ms时将一个消息对象添加到消息队列队列中,(注意是绝对时间)
* 基础时间是指调用时的{@link android.os.SystemClock#uptimeMillis}.如果手机进入休眠状态,将会增加额外的时间延迟。
*
* @param uptimeMillis 消息应该投递至消息队列中的绝对时间,使用{@link android.os.SystemClock#uptimeMillis}作为基础时间
* @return 当Runnable实现类对象r成功添加到消息队列中返回true, 失败时则返回false, 通常是因为处理消息队列的Looper不存在
* * 注意:返回true并不代表Runnable会被执行,比如如果Looper被quit()在消息被分发时,会导致队列中的所有消息都被丢弃
*/
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);
}
/**
* 将发送一个Runnable实现类到队列队首,消息将在下一次循环时首先执行
* 此方法仅用于非常特殊的情况下使用,它会带来排序问题以及其他副作用
**/
public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
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, 0);
}
/**
* 如果此方法在Looper的同一线程中调用,则同步执行消息,否则则调用{@link #sendMessage}将消息投递到消息队列中
*
* @hide 不对外开放,无法通过SDK调用
*/
public final boolean executeOrSendMessage(@NonNull Message msg) {
if (mLooper == Looper.myLooper()) {
dispatchMessage(msg);
return true;
}
return sendMessage(msg);
}
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);
}
/**
* 将所有what与传入值一致的未分发消息从消息队列中删除
*/
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
/**
* 删除消息队列中what等于传入值,且obj值等于传入的object值的消息。如果object等于null,则所有的消息都会被删除
*/
public final void removeMessages(int what, @Nullable Object object) {
mQueue.removeMessages(this, what, object);
}
/**
*@hide
*/
public final void removeEqualMessages(int what, @Nullable Object object) {
mQueue.removeEqualMessages(this, what, object);
}
/**
* Remove any pending posts of callbacks and sent messages whose
* <var>obj</var> is <var>token</var>. If <var>token</var> is null,
* all callbacks and messages will be removed.
*/
public final void removeCallbacksAndMessages(@Nullable Object token) {
mQueue.removeCallbacksAndMessages(this, token);
}
/**
*@hide
*/
public final void removeCallbacksAndEqualMessages(@Nullable Object token) {
mQueue.removeCallbacksAndEqualMessages(this, token);
}
/**
* Check if there are any pending posts of messages with code 'what' in
* the message queue.
*/
public final boolean hasMessages(int what) {
return mQueue.hasMessages(this, what, null);
}
/**
* Return whether there are any messages or callbacks currently scheduled on this handler.
* @hide
*/
public final boolean hasMessagesOrCallbacks() {
return mQueue.hasMessages(this);
}
/**
* 判断消息队列中是否有未处理的what值和Obj值与传入的形参一致的
*/
public final boolean hasMessages(int what, @Nullable Object object) {
return mQueue.hasMessages(this, what, object);
}
/**
*@hide
*/
public final boolean hasEqualMessages(int what, @Nullable Object object) {
return mQueue.hasEqualMessages(this, what, object);
}
/**
* Check if there are any pending posts of messages with callback r in
* the message queue.
*/
public final boolean hasCallbacks(@NonNull Runnable r) {
return mQueue.hasMessages(this, r, null);
}
// if we can get rid of this method, the handler need not remember its loop
// we could instead export a getMessageQueue() method...
@NonNull
public final Looper getLooper() {
return mLooper;
}
@Override
public String toString() {
return "Handler (" + getClass().getName() + ") {"
+ Integer.toHexString(System.identityHashCode(this))
+ "}";
}
@UnsupportedAppUsage
final IMessenger getIMessenger() {
synchronized (mQueue) {
if (mMessenger != null) {
return mMessenger;
}
mMessenger = new MessengerImpl();
return mMessenger;
}
}
private final class MessengerImpl extends IMessenger.Stub {
public void send(Message msg) {
msg.sendingUid = Binder.getCallingUid();
Handler.this.sendMessage(msg);
}
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
// 构建Message对象
@UnsupportedAppUsage
private static Message getPostMessage(Runnable r, Object token) {
Message m = Message.obtain();
m.obj = token;
m.callback = r;
return m;
}
private static void handleCallback(Message message) {
message.callback.run();
}
private static final class BlockingRunnable implements Runnable {
private final Runnable mTask;
private boolean mDone;
public BlockingRunnable(Runnable task) {
mTask = task;
}
@Override
public void run() {
try {
mTask.run();
} finally {
synchronized (this) {
mDone = true;
notifyAll();
}
}
}
public boolean postAndWait(Handler handler, long timeout) {
if (!handler.post(this)) {
return false;
}
synchronized (this) {
if (timeout > 0) {
final long expirationTime = SystemClock.uptimeMillis() + timeout;
while (!mDone) {
long delay = expirationTime - SystemClock.uptimeMillis();
if (delay <= 0) {
return false; // timeout
}
try {
wait(delay);
} catch (InterruptedException ex) {
}
}
} else {
while (!mDone) {
try {
wait();
} catch (InterruptedException ex) {
}
}
}
}
return true;
}
}
}