Android Handler消息机制03-Message源码学习
Posted 双木青橙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Handler消息机制03-Message源码学习相关的知识,希望对你有一定的参考价值。
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,且也只对应一个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实现以上是关于Android Handler消息机制03-Message源码学习的主要内容,如果未能解决你的问题,请参考以下文章