android handler取消,Android Handler机制8之消息的取出与消息的其他操作

本文详细介绍了Android Handler机制中的消息取出和移除过程,包括Looper的loop方法、Message的next方法以及如何关闭消息队列。重点讲解了MessageQueue的next()方法,包括其对障栅消息的处理、阻塞与唤醒机制,以及如何通过dispatchMessage(msg)处理消息。此外,还讨论了如何取消消息和关闭消息队列的方法,以及查看消息是否存在和阻塞非安全执行的情况。
摘要由CSDN通过智能技术生成

Android Handler机制系列文章整体内容如下:

本片文章的主要内容如下:

1、消息的取出

2、消息(Message)的移除

3、关闭消息队列

4、查看消息是否存在

5、阻塞非安全执行

一、消息的取出

(一)、消息的取出主要是通过Looper的loop方法

/**

* Run the message queue in this thread. Be sure to call

* {@link #quit()} to end the loop.

*/

public static void loop() {

//第1步

final Looper me = myLooper();

if (me == null) {

throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");

}

//第2步

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();

//第3步

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);

}

final long traceTag = me.mTraceTag;

if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {

Trace.traceBegin(traceTag, msg.target.getTraceName(msg));

}

try {

// 第5步

msg.target.dispatchMessage(msg);

} finally {

if (traceTag != 0) {

Trace.traceEnd(traceTag);

}

}

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);

}

// 第6步

msg.recycleUnchecked();

}

}

第1步 获取Looper对象

第2步 获取MessageQueue消息队列对象

第3步 while()死循环遍历

第4步 通过queue.next()来从MessageQueue的消息队列中获取一个Message msg对象

第5步 通过msg.target. dispatchMessage(msg)来处理消息

第6步 通过msg.recycleUnchecked()方来回收Message到消息对象池中

由于第1步、第2步和第3步比较简单就不讲解了,而第6步在y已经讲解过,也不讲解了,下面我们来重点说下第4步和第5步

(二)、Message next()方法

从消息队列中提取Message交给Looper来处,这个步骤应该是MessageQueue乃至整个线程消息机制的核心了,所以我们将这部分放到最后来将,因为其内部的代码逻辑比较复杂,涉及到了障栅如何拦截同步消息、如何阻塞线程、如何在空闲的时候执行IdleHandler以及如何关闭Looper等内容,在源码已经做了详细的注释,不过由于逻辑比较复杂所以想要看明白,大家还要花费一定时间的。

PS:在Looper.loop()中获取消息的方式就是调用next()方法。

Message next() {

// Return here if the message loop has already quit and been disposed.

// This can happen if the application tries to restart a looper after quit

// which is not supported.

// 如果消息循环已经退出了。则直接在这里return。因为调用disposed()方法后mPtr=0

final long ptr = mPtr;

if (ptr == 0) {

return null;

}

//记录空闲时处理的IdlerHandler的数量

int pendingIdleHandlerCount = -1; // -1 only during first iteration

// native层用到的变量 ,如果消息尚未到达处理时间,则表示为距离该消息处理事件的总时长,

// 表明Native Looper只需要block到消息需要处理的时间就行了。 所以nextPollTimeoutMillis>0表示还有消息待处理

int nextPollTimeoutMillis = 0;

for (;;) {

if (nextPollTimeoutMillis != 0) {

//刷新下Binder命令,一般在阻塞前调用

Binder.flushPendingCommands();

}

// 调用native层进行消息标示,nextPollTimeoutMillis 为0立即返回,为-1则阻塞等待。

nativePollOnce(ptr, nextPollTimeoutMillis);

//加上同步锁

synchronized (this) {

// Try to retrieve the next message. Return if found.

// 获取开机到现在的时间

final long now = SystemClock.uptimeMillis();

Message prevMsg = null;

// 获取MessageQueue的链表表头的第一个元素

Message msg = mMessages;

// 判断Message是否是障栅,如果是则执行循环,拦截所有同步消息,直到取到第一个异步消息为止

if (msg != null && msg.target == null) {

// 如果能进入这个if,则表面MessageQueue的第一个元素就是障栅(barrier)

// Stalled by a barrier. Find the next asynchronous message in the queue.

// 循环遍历出第一个异步消息,这段代码可以看出障栅会拦截所有同步消息

do {

prevMsg = msg;

msg = msg.next;

//如果msg==null或者msg是异步消息则退出循环,msg==null则意味着已经循环结束

} while (msg != null && !msg.isAsynchronous());

}

// 判断是否有可执行的Message

if (msg != null) {

// 判断该Mesage是否到了被执行的时间。

if (now < msg.when) {

// Next message is not ready. Set a timeout to wake up when it is ready.

// 当Message还没有到被执行时间的时候,记录下一次要执行的Message的时间点

nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);

} else {

// Message的被执行时间已到

// Got a message.

// 从队列中取出该Message,并重新构建原来队列的链接

// 刺客说明说有消息,所以不能阻塞

mBlocked = false;

// 如果还有上一个元素

if (prevMsg != null) {

//上一个元素的next(越过自己)直接指向下一个元素

prevMsg.next = msg.next;

} else {

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值