1.概念
Handler主要用于线程之间的通信,例如刷新主界面UI等,其通信流程图如下:
在这个过程中,Handler即作为发起者也作为终结者,Message作为基本信息载体,MessageQueue作为消息体的集合,Looper将这三者串联起来。
2.Message
2.1概念 message
官方解释: 包含任意类型的对象和描述信息,可以被发送给 Handler。(官方文档:https://developer.android.com/reference/android/os/Message)
2.2Message中关键变量
1.What用于标识Message具体是做什么的
2.arg1、arg2用于存储简单的整型数据
3.Bundle用于存储复杂的数据
4.跨进程通信绑定数据的 object(主要应用在Messenger跨进程通信https://blog.csdn.net/qq_16736297/article/details/85618729)
5.与之关联的Handler
6.另外就是一些标志位
具体详细的变量介绍如下:
/**
* 用来标识消息身份ID,接收消息方可以根据这个身份ID知道这个消息是做什么的
*/
public int what;
/**
* 如果你的消息要传递的数据是整型的,可以直接使用 arg1 和 arg2,而不需要使用构造一个 Bundle
*/
public int arg1;
public int arg2;
/**
* 一个任意类型的对象,在使用 Messenger 跨进程传递消息时,通常使用它传递给接收者
* 在其他场景下我们一般使用 setData() 方法
* 具体适用场景可以去访问()
*/
public Object obj;
/**
* 负责回复消息的 Messenger,有的场景下(比如接受者、发送者模型)需要使用它
*/
public Messenger replyTo;
/**
* 当前消息的标志,只在被 Messenger 传递消息时使用,其他情况下都是 -1
*/
public int sendingUid = -1;
//标识当前消息是否在被使用
//当一个消息入队时这个标志会被改变,在被重新获取后重置
//当一个消息已经在被使用时,二次入队或者回收会报错(这就是我前言中提到的错误原因)
/*package*/static final int FLAG_IN_USE = 1 << 0;
//标识当前 消息是否是异步的
/*package*/static final int FLAG_ASYNCHRONOUS = 1 << 1;
//在 copyFrom 方法中要清除的标志
/*package*/static final int FLAGS_TO_CLEAR_ON_COPY_FROM = FLAG_IN_USE;
/*package*/int flags;
/*package*/long when;
//很关键的数据部分
/*package*/Bundle data;
//发送和处理消息关联的 Handler
/*package*/Handler target;
//消息的回调
/*package*/Runnable callback;
//在有些场景下还会以链表的形式关联后一个消息
/*package*/Message next;
//消息池
private static final Object sPoolSync = new Object();
/**
* 回收消息链表
*/
private static Message sPool;
private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 50;
/**
* 是否回收标志位
*/
private static boolean gCheckRecycle = true;
2.3Message的获取方式
在官方文档中Message中的有如下两种:
1.Message.obtain();
2.Handler.obtainMessage();
需要注意的是Message的构造函数是public,但这里并没有去创建,而是选择利用上面的这两种方式从消息池中获取,这样做的原因是为了节省内存。
另外这两种获取方式本质上并没有什么区别,从下面的源码中可得知Handler.obtainMessage()还是调用了Message.obtain()
/**
* Returns a new {@link android.os.Message Message} from the global message pool. More
*efficient than
*creating and allocating new instances. The retrieved message has its handler set to
*this instance (Message.target == this).
*If you don't want that facility, just call Message.obtain() instead.
*/
public final Message obtainMessage()
{
return Message.obtain(this);
}
2.4Message.obtain()分析
Message.obtain()在Message中有7个重载方法,此处只分析最复杂的一个,具体源码如下:
public static Message obtain(Handler h, int what,
int arg1, int arg2, Object obj) {
Message m = obtain();
m.target = h;
m.what = what;
m.arg1 = arg1;
m.arg2 = arg2;
m.obj = obj;
return m;
}
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static 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;
}
}
return new Message();
}
可以看到,这个方法会获取前面提到的 private static Message sPool;
,如果 sPool
存在就从复用消息链表头部取一个消息,然后重置它的标志位;如果不存在复用消息链表就新建一个消息。
既然消息是从消息池中添加,那么问题来了,消息是何时添加的呢?
2.5Message的回收利用
看下面的源码
void recycleUnchecked() {
flags = FLAG_IN_USE;//信息标志位flag,当信息被使用时,会被标志为FLAG_IN_USE
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = -1;
when = 0;
target = null;
callback = null;
data = null;
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
recycleUnchecked()方法将Message的flag赋值为FLAG_IN_USE,如果此时被标记过的Message再次被放进队列,就会报错this message is already in use。当然此时Message所承载的数据也被清除,然后将其放入消息回收池中,以待下次使用。
那么问题又来了,recycleUnchecked()何时会被调用呢?扒开源码,我们会发现此方法在MessageQueue
和 Looper中都有使用,
MessageQueue.removeMessages()的源码如下:
void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}
synchronized (this) {
Message p = mMessages;
// Remove all messages at front.
while (p != null && p.target == h && p.what == what
&& (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycleUnchecked();//在此处调用
p = n;
}
// Remove all messages after front.
while (p != null) {
Message n = p.next;
if (n != null) {
if (n.target == h && n.what == what
&& (object == null || n.obj == object)) {
Message nn = n.next;
n.recycleUnchecked();//此处有调用
p.next = nn;
continue;
}
}
p = n;
}
}
}
而Looper.loop()方法中有调用:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this
thread.");
}
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 msg = queue.next(); // might block
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);
}
//此处省略部分代码
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);
}
msg.recycleUnchecked();//在此处调用了recycleUnchecked()方法;
}
}
从MessageQueue.removeMessages()和
Looper.loop()方法中可以看出,此处当消息被移除消息队列时或者被Looper处理以后就会被标识为FLAG_IN_USE,然后被放入消息回收池中,当我们再次使用时,会通过Message.obtain()到消息链表进行获取。
那么问题再次来了,什么是消息回收池,所谓的消息池用于存放还未处理的消息
3.MessageQueue
MessageQueue是一个管理Message的消息列表,由Handler为其添加Message,由Looper进行取出。
3.1Message的主要关键变量
// 队列是否可以退出
private final boolean mQuitAllowed;
@SuppressWarnings("unused")
private long mPtr; //底层使用的 code
//消息链表的开头
Message mMessages;
private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
private SparseArray<FileDescriptorRecord> mFileDescriptorRecords;
private IdleHandler[] mPendingIdleHandlers;
private boolean mQuitting;
//指出获取下一个消息的方法 next() 是否阻塞
private boolean mBlocked;
// Barriers are indicated by messages with a null target whose arg1 field carries the
token.
//后一个屏障的 token
private int mNextBarrierToken;
MessageQueue其实类似于LinkList列表,持有消息列表的一个节点
3.2MessageQueue的初始化
MessageQueue是不能直接被访问,而是通过Looper.myQueue()方法进行获取,源码如下:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
可以从MessageQueue的构造函数中看出,其构造函数传入一个是否中途撤出的标志位,有native层初始化。
当我们获取MessageQueue之后,开始向其添加Message
3.3消息入队的过程
Message入队通过enqueueMessage()方法,让我们来一起扒拉扒拉这个方法的源码:
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {//此处必须给Message设置一个目标,即与他相关联的Handler
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;
}
msg.markInUse();//Message入队以后就会被标记为被使用
msg.when = when;
Message p = mMessages;
boolean needWake;
//添加消息到链表中
if (p == null || when == 0 || when < p.when) {
//空链表的时候读取信息会被堵塞,新添加消息后唤醒
msg.next = p;
mMessages = msg;
needWake = mBlocked;
} else {
//插入消息到队列时,只有在队列头部有个屏障并且当前消息是异步的时才需要唤醒队列
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; // invariant: p == prev.next
prev.next = msg;
}
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
在此方法中,有一步检查消息是否被使用,是的话会报错,具体如下:
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
由上可知当我们在Handler.sendMessage()时,必须Message.obtain()或者new Message()对象。当然,如果已退出队列再次添加也会报错。说完消息进队,下面该讲消息如何出队
3.4消息出队
Message的出队是有MessageQueue.next()方法进行,接下来我们开始进行撸码行动
Message next() {
// 如果消息的Looper退出,就退出这个方法
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0;
//循环,有消息就返回,没有消息就阻塞
for (;;) {
//如果有过段时间在需要要处理的消息,就先调用Binder的这个方法
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// 获取下一个消息
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;//当前链表的头节点
if (msg != null && msg.target == null) {
//如果消息没有 target,那它就是一个屏障,需要一直往后遍历找到第一个异
//步的消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
if (msg != null) {
if (now < msg.when) {
// //如果这个消息还没到处理时间,就设置个时间过段时间再处理
nextPollTimeoutMillis = (int) Math.min(msg.when - now,
Integer.MAX_VALUE);
} else {
// 消息是正常的、可以立即处理的
mBlocked = false;
//取出当前消息,链表头结点后移一位
if (prevMsg != null) {
prevMsg.next = msg.next;
} else {
mMessages = msg.next;
}
msg.next = null;
if (DEBUG) Log.v(TAG, "Returning message: " + msg);
msg.markInUse();//标记这个消息在被使用
return msg;
}
} else {
// 消息链表里没有可以处理的消息了
nextPollTimeoutMillis = -1;
}
//如果收到退出的消息,并且所有等待处理的消息都处理完时,调用 Native 方法销毁队列
if (mQuitting) {
dispose();
return null;
}
//有消息等待过段时间执行时,pendingIdleHandlerCount 增加
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// Run the idle handlers.
// We only ever reach this code block during the first iteration.
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
pendingIdleHandlerCount = 0;
// While calling an idle handler, a new message could have been delivered
// so go back and look again for a pending message without waiting.
nextPollTimeoutMillis = 0;
}
}
由上可知,在next()方法里有一个循环,循环的目的是找到消息链表中一个可以处理的,target不为空的并且可执行的事件不再未来的消息就返回,否则继续找,当然如果无任何消息或者未来一段时间在处理,这时会将mBlock这个标量置为true,然后在下一个Message判断进队时就会判断这个Message的位置,如果在队首就会调用 nativeWake() 方法唤醒线程!
在有关堵塞的问题上,我们发现MessageQueue.java中有一个IdleHandler,这个方法是干嘛用的呢
public static interface IdleHandler {
/**
* 1.消息队列没有消息时,就会调用这方法,阻塞等待消息进入
* 2.返回true的话表示唤醒堵塞线程,false表示移除
* 3.如果消息队列中有消息等待在将来执行,也会调用这个方法
*/
boolean queueIdle();
}
根据注释和源码可知,IdleHandler是一个线程阻塞时回调的接口。当然在MessageQueue提供监听阻塞回调的注册和移除接口:
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}
public void removeIdleHandler(@NonNull IdleHandler handler) {
synchronized (this) {
mIdleHandlers.remove(handler);
}
}
但消息队列被阻塞时,会回调监听阻塞的观察者,告诉他们:“我有空了,赶紧嗨起来!!!”
4.Looper
4.1概念:Looper 是用于运行一个线程中的消息的类。
4.2Looper的关键属性
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // 主线程中的 Looepr
final MessageQueue mQueue; //与之管理的消息队列
final Thread mThread; //所在的线程
private Printer mLogging;
private long mTraceTag;
4.3线程相关的ThreadLocal
在线程如何通过Looper.prepare()创建一个Looper
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
通过上述代码可知,每个线程只有一个Looper,而创建Looper都需要通过ThreadLocal,那ThreadLocal又是何方神圣呢,我们来扒拉扒拉其中主要的源码:
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
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);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
从上面的源码set和get中有一个ThreadLocalMap,这个ThreadLocalMap里持有一个Entry,撸下源码:
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
从上面的源码,可以看出ThreadLocal先通过当前线程获取一个ThreadLocalMap,然后在ThreadLocalMap中保存ThreadLocal和数据的关联。ThreadLocalMap类似于Map。
4.4无限循环调度
通常在线程创建Looper对象以后,就可以调度Looper.loop()方法了,具体的源码如下:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) { //当前线程必须创建 Looper 才可以执行
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
//底层对 IPC 标识的处理,不用关心
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) { //无限循环模式
Message msg = queue.next(); //从消息队列中读取消息,可能会阻塞
if (msg == null) { //当消息队列中没有消息时就会返回,不过这只发生在 queue 退出的时候
return;
}
//...
try {
msg.target.dispatchMessage(msg); //调用消息关联的 Handler 处理消息
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
//...
msg.recycleUnchecked(); //标记这个消息被回收
}
}
pasted:https://blog.csdn.net/u011240877/article/details/72892321
由上可知,Looper.loop(),通过MessageQueue.next()取出信息,如果没有消息的话的会阻塞,直到有新的消息进入或者消息队列退出。
当拿到消息后,调用消息相关联的Handler处理。
既然能开启循环那么如何终止循环呢
4.5退出循环
在源码注释中就提到,当开启循环后,不要忘记调用quit()方法终止循环。
退出循环有两个方法在Looper里,quit和quitSafely的源码
public void quit() {
mQueue.quit(false);
}
public void quitSafely() {
mQueue.quit(true);
}
而两种方式里调用的最终都是MessageQueue.quit(boolean),具体如下:
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
// We can assume mPtr != 0 because mQuitting was previously false.
nativeWake(mPtr);
}
}
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
if (p.when > now) { //`如果链表头部的消息执行时间在将来(也就是一时半会儿没有任务可执行)
removeAllMessagesLocked(); //就直接强硬的全部回收了
} else {
Message n;
for (;;) { //否则找到那个执行时间大于现在的消息,把它后面的消息都回收了
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
private void removeAllMessagesLocked() {
Message p = mMessages;
while (p != null) { //挨个遍历链表,把消息都回收了
Message n = p.next;
p.recycleUnchecked();
p = n;
}
mMessages = null;
}
plaste:https://blog.csdn.net/u011240877/article/details/72892321
从上述源码可以看出,这两种方式的区别
1.quit():立即把消息链表中的消息都回收掉
a.在停止后,如果Handler还发送消息,就会返回false,入队失败
b.由此也可得出此方法并不安全
2.quitSafely():
a.只会将未执行的消息回收掉
b.在调用之后添加的消息,不会被处理,Handler.sendMessage()也会返回false
当消息队列表标记退出状态时,他的next()方法会返回null,于是Looper.loop()循环就结束了
5.Handler
在介绍完Looper、MessageQueue,Message之后,接着该主角登场了,作为最终的发起者和结束者,Handler又是何方神圣呢?
Handler所做的就是切换线程:
a.在子线程中将Message或者Runable发送到发送到消息队列MessageQueue中。
b.然后等待Looper调度这个Message之后,再度召唤Handler来处理。
c.这时消息已经在创建Handler的线程了
接下来我们逐步分析Handler是如何实现线程间的切换的
5.1Handler的关键属性变量
final Looper mLooper;
final MessageQueue mQueue;
final Callback mCallback;
final boolean mAsynchronous;
IMessenger mMessenger;
由上不难发现,Handler属性十分简单,其中Callback可以作为构造函数的参数创建Handler,
public Handler(Callback callback) {
this(callback, false);
}
public interface Callback {
public boolean handleMessage(Message msg);
}
paste:https://blog.csdn.net/u011240877/article/details/72892321
平时我们在使用Handler中,一般都是创建Handler的子类,然后重写其handleMessage()方法,现在可以通过Callback()构建Handler,如下:
Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
//这里处理消息
return false;
}
});
paste:https://blog.csdn.net/u011240877/article/details/72892321
但是这种方式容易造成内存泄露,因为是匿名内部类,持有外部引用。
OK,了解Handler的如何创建之后,那Handler是如何发送信息
5.2发送信息
Handler发送的数据类型有两种:Message和Runnable
发送方式有两种post和send,post发送的是Runnable,而send发送的是Message,但Runnable最终也会转成Message:
public final boolean post(Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
有上述源码可知,我们直接去扒拉sendMessage源码
public final boolean sendMessage(Message msg){
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(Message msg, long delayMillis){
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(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(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
由上面的源代码中可知,handler在发送消息后最终调用了MessageQueue.enqueueMessage()方法。
而我们最常使用的Handler.sendMessagedDelayed()发送延迟消息后,其实在最后入队后指定这个Message的msg.when(),在MessageQueue.next()方法中,会对msg.when>now的消息作出延迟处理,其具体实现在Native层。
当消息入队后,由Looper启动后,循环取出消息,交给target.dispatchMessage(),即Handler.dispatchMessage()来处理消息,其具体的源码如下:
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
public void handleMessage(Message msg) {
}
有上述源码可知,Handler在处理消息时有三种情况:
a.当msg.callback不为空时
a.这在使用post方式发送消息时,会发生
b.直接调用Runnable的run方法
b.当mCallback不为空时
a.这在之前的源码分析中我们曾提到,当Handler.callBack为参数构造Handler时调用
b.那就调用构造函数里传入handlerMessage()方法
c.如果返回true就不行再往下执行。
c.最后调用handleMessage()这是一个空实现,需要我们在Handler子类里面重写。
5.3移除信息
由于发送时可以发送 Callback 和 Message,所以取消也有两种:
- removeCallbacks()
- removeMessages()
看一下源码发现调用的其实就是消息队列的出队方法:
public final void removeCallbacks(Runnable r){
mQueue.removeMessages(this, r, null);
}
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
至此结束:
参考:
1.Android艺术探索