Android 源码解析(02) Handler机制详解
程序员文章站
2022-03-08 11:37:15
...
很多Android初学者对Handler很不明白,其实Handler就是基于消息队列的一个异步消息处理机制,应用于线程之间的通讯。
本文就对该机制进行详细讲解,主要分为三部分:
1、相关概念和流程讲解;
2、利用纯java实现一套简易的Handler机制;
3、Android原生Handler讲解
一个Looper对应一个或者多个Handler;
一个Handler只能对应一个Looper,该Handler发送的消息将加入到对应Looper所对应的MessageQueue
一条消息对应一个Handler,该消息由该Handler发送和处理;
一个Handler可以发送和处理多条消息
2、Looper初始化过程将初始化一个独有MessageQueue
3、Looper启动(Looper.loop())
4、处理线程 调用MessageQueue获取下一条消息处理(获取不到下一条消息将阻塞直到有下一条消息)
5、发送线程 利用 处理线程的Looper初始化一个Handler(该Handler也将得到对应的MessageQueue),并实现处理消息的代码
6、发送线程 利用Handler发送消息,该消息将插入Handler对应的Looper对应的MessageQueue,触发步骤4获取到下一条消息
7、步骤4获取到消息之后,该消息将由处理线程分发到到处理代码进行处理
运行结果:
time:1500475211257; send msg thread: Thread-0
time:1500475211258; thread:handleThread; message what:1
time:1500475213258; thread:handleThread; message what:2
至此,我们已经用纯java的api实现了一个Android的Handler机制,如果你理解了上面所讲解的,那你也基本理解了Android的Handler机制
上面有的原生也都有,可以说原生就是上面的高级版本,增加了一些附加功能和重载一下api使得调用更方便。
下一节我就说说Android原生Handler机制与上面的例子(下文我们称为Demo)不同之处
主要代码如下:
IdleHandler是MessageQueue的一个静态内部接口,里面只有一个方法,源码如下:
当它插入到消息队列,那么之后的同步消息将不会执行(异步消息可以执行),直到该同步消息分割栏被移除。同步消息和异步消息就是消息中的一个标志不同
用户发送的消息默认都是同步消息,发送异步消息、插入和移除同步分割栏API都被SDK隐藏了,若要使用此功能只能通过反射机制调用(后文会讲到)
该功能主要用于系统处理一些重要事情的时候可以先不处理用户发的消息。
插入和移除同步分割栏方法:
获取下一条消息源码:
移除消息源码:
其他源码读者自己去看
a、如果消息带有callback对象,则直接回调callback对象,完成处理;
b、如果消息没有callback对象,则判断Handler是否有全局callback对象,
有则回调(该回调具有boolean类型的返回值,true表示你已经处理了消息,不希望其他处理)
c、Handler没有全局callback对象,或者回调返回false,则调用Handler的handleMessage处理
参数:r:将要运行的代码抽象
timeout:等待超时时间
步骤:
a、postAndWait将自己post到相应队列,相应队列已经退出返回false
b、然后等待利用wait方法阻塞等待
c、run方法运行,也就是处理线程处理了自己,就调用任务的run方法,然后通知wait唤醒
d、postAndWait返回true
源码如下:
然后我还说用户默认发送的都是同步消息,那怎么样才能发送异步消息呢?我们就看看发送消息的源码:
原来构造方法可以指定:
当然也增加了插入和移除同步分割栏的方法:
到这里我们已经将Android的Handler机制和源码都讲完了,不知道小伙伴是否理解了呢?
本文就对该机制进行详细讲解,主要分为三部分:
1、相关概念和流程讲解;
2、利用纯java实现一套简易的Handler机制;
3、Android原生Handler讲解
相关概念
1、Message
消息,通讯的数据单元。2、线程
消息的发送者(下文统称发送线程)和处理者(下文统称处理线程)。当然线程也可以自己给自己发消息,这样发送线程和处理线程将是同一个3、MessageQueue
消息队列,用来存放通过Handler发布的消息。提供获取下一条消息和插入以及移除消息的各种API4、Handler
Message的发送者和处理者,负责将Message添加到消息队列以及接受消息队列中的Message进行处理。5、Looper
消息泵,依次取出Message Queue里面的Message,并交付给相应的Handler进行处理。关系
处理线程、Looper和MessageQueue一一对应;一个Looper对应一个或者多个Handler;
一个Handler只能对应一个Looper,该Handler发送的消息将加入到对应Looper所对应的MessageQueue
一条消息对应一个Handler,该消息由该Handler发送和处理;
一个Handler可以发送和处理多条消息
机制大体过程
1、处理线程启动,初始化一个独有Looper2、Looper初始化过程将初始化一个独有MessageQueue
3、Looper启动(Looper.loop())
4、处理线程 调用MessageQueue获取下一条消息处理(获取不到下一条消息将阻塞直到有下一条消息)
5、发送线程 利用 处理线程的Looper初始化一个Handler(该Handler也将得到对应的MessageQueue),并实现处理消息的代码
6、发送线程 利用Handler发送消息,该消息将插入Handler对应的Looper对应的MessageQueue,触发步骤4获取到下一条消息
7、步骤4获取到消息之后,该消息将由处理线程分发到到处理代码进行处理
利用纯java实现一套简易的Handler机制
由于是简易版本,为了使读者能更好理解基本原理流程,所以我只提供了最基本的一些功能1、Message类
public final class Message {
/** 消息携带的处理数据(Demo只携带一个整型数据) **/
public int what;
/** 以下3个字段属于内部标志属性 **/
/** 消息处理期望时刻,用于消息队列对消息排序和处理时机的判断,
* 需要插入队列头部就将该参数设置为0,通常赋值为发送时间 **/
long when;
/** 消息发送和处理的Handler **/
Handler target;
/** 消息队列中下一条消息的引用 **/
Message next;
/** 获取消息API **/
public static Message obtain() {
return new Message();
}
public static Message obtain(Handler h) {
Message m = obtain();
m.target = h;
return m;
}
}
2、MessageQueue类
public final class MessageQueue {
/** 消息队列头引用,也是下一条要处理消息的引用 **/
Message mMessages;
/** 标志当前队列是否处于阻塞状态 **/
private boolean mBlocked;
MessageQueue() {
}
/** 获取下一条消息,如果没有下一条能处理的消息将阻塞直到有下一条消息,线程被终止返回null **/
Message next() {
/** 等待时间。<0:表示不阻塞;0:表示一直阻塞直到被notify;其他数据表示阻塞时间。默认-1 **/
int nextPollTimeoutMillis = -1;
/** 利用死循环一直获取下一条消息,获取不到将阻塞 **/
for (;;) {
synchronized (this) {
if (nextPollTimeoutMillis >= 0) {
/** 不为负数将阻塞 **/
try {
mBlocked = true;
wait(nextPollTimeoutMillis);
} catch (InterruptedException e) {
return null;
}
}
final long now = System.currentTimeMillis();
/** 判断队列头消息 **/
Message msg = mMessages;
if (msg != null) {
if (now < msg.when) {
/** 队列头消息处理时间还没到,需要等待 **/
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
/** 队列头消息处理时间已到,队列头引用后移,前队列头消息脱离队列并返回 **/
mBlocked = false;
mMessages = msg.next;
msg.next = null;
return msg;
}
} else {
/** 队列为空,将等待 **/
nextPollTimeoutMillis = 0;
}
}
}
}
/** 消息入列方法,when为该消息处理的期望时刻 **/
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
/** 将期望时刻复制到消息对应的属性上 **/
msg.when = when;
/** 获取当前队列头消息 **/
Message p = mMessages;
if (p == null || when == 0 || when < p.when) {
/** 如果队列头为空(也就是队列为空)
* 或者将要插入的消息的期望处理时刻为0
* 或者比队列消息头期望处理时刻还早,那就插入到队列头 **/
msg.next = p;
mMessages = msg;
} else {
/** 查找对应位置插入 **/
Message prev;
for (;;) {
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
}
msg.next = p;
prev.next = msg;
}
if (mBlocked) {
/** 插入完毕,如果当前阻塞则唤醒 **/
notifyAll();
}
}
return true;
}
}
3、Handler类
public class Handler {
/** 处理线程对应的消息队列 **/
final MessageQueue mQueue;
/** 处理线程对应的消息获取泵 **/
final Looper mLooper;
/** 处理消息函数(一般需要子类重写来处理消息) **/
public void handleMessage(Message msg) {
}
/** 消息分发,直接调用处理函数消息 **/
void dispatchMessage(Message msg) {
handleMessage(msg);
}
public Handler(Looper looper) {
mLooper = looper;
mQueue = looper.mQueue;
}
/** 获取 消息 **/
public final Message obtainMessage() {
return Message.obtain(this);
}
/** 立刻发送消息 **/
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, System.currentTimeMillis() + delayMillis);
}
/** 指定时刻发送消息(其实也是立刻发送,只是控制了处理时刻) **/
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
/** 将消息发送到队列头(也就是期望处理时间设置为0) **/
public final boolean sendMessageAtFrontOfQueue(Message msg) {
MessageQueue queue = mQueue;
if (queue == null) {
return false;
}
return enqueueMessage(queue, msg, 0);
}
/** 内部发送消息方法 **/
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
return queue.enqueueMessage(msg, uptimeMillis);
}
}
4、Looper类
public final class Looper {
/** 线程私有数据,用于保存线程对应的Looper。底下会建立一个Map,将线程与Looper实现映射关系 **/
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
/** 该Looper对应的消息队列 **/
final MessageQueue mQueue;
/** 该Looper对应的处理线程 **/
final Thread mThread;
/** 初始化函数。该函数由哪一个线程调用,将为该线程初始化一个Looper **/
public static void prepare() {
if (sThreadLocal.get() != null) {
/** 该 线程已经映射了一个Looper了,抛出异常 **/
throw new RuntimeException("Only one Looper may be created per thread");
}
/** 初始化一个Looper,并利用ThreadLocal关联关系 **/
sThreadLocal.set(new Looper());
}
/** 启动消息泵,获取和处理消息。该函数由哪一个线程调用,将是启动该线程的消息泵 **/
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;
/** 利用死循环获取和处理消息 **/
for (;;) {
/** 获取下一条消息,如果没有下一条能处理的消息将阻塞直到有下一条消息 **/
Message msg = queue.next();
if (msg == null) {
return;
}
/** 将该消息交由对应的Handler处理 **/
msg.target.dispatchMessage(msg);
}
}
/** 返回本县城对应的Looper **/
public static Looper myLooper() {
return sThreadLocal.get();
}
private Looper() {
mQueue = new MessageQueue();
mThread = Thread.currentThread();
}
public Thread getThread() {
return mThread;
}
}
5、 消息处理线程
为了使用方便我们扩展了线程作为处理线程,使其带有Looper
class LooperThread extends Thread {
/** 保存该线程对应的Looper **/
Looper mLooper;
public LooperThread(String name) {
super(name);
}
@Override
public void run() {
/** 初始化Looper **/
Looper.prepare();
synchronized (this) {
/** 初始化Looper,并通知唤醒等待者(getLooper可能存在等待) **/
mLooper = Looper.myLooper();
notifyAll();
}
/** 启动消息泵,处理或者等待处理消息 **/
Looper.loop();
}
/** 获取消息处理线程对应的消息泵(该方法一般为发送线程调用),
* 由于该消息泵为消息处理线程之后才能初始化,
* 考虑到获取的是的时候可能还没有初始化,所以内部利用循环等待方式获取 **/
public Looper getLooper() {
/** 如果线程已死,则返回空 **/
if (!isAlive()) {
return null;
}
synchronized (this) {
/** 循环等待 **/
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
}
6、测试类
public class AHandlerTest {
public static void main(String[] args) {
/** 创建,启动 消息处理线程 **/
LooperThread ht = new LooperThread("handleThread");
ht.start();
/** 创建Handler,并重写处理消息方法 **/
final Handler h1 = new Handler(ht.getLooper()) {
@Override
public void handleMessage(Message msg) {
System.out.println(
"time:" + System.currentTimeMillis() +
"; thread:" + Thread.currentThread().getName() +
"; message what:" + msg.what);
}
};
/** 创建,启动 消息发送线程 **/
new Thread() {
public void run() {
System.out.println(
"time:" + System.currentTimeMillis() +
"; send msg thread: " + Thread.currentThread().getName());
/** 发送立即消息 **/
Message msg1 = h1.obtainMessage();
msg1.what = 1;
h1.sendMessage(msg1);
/** 发送延时时间为2秒的延时消息 **/
Message msg2 = h1.obtainMessage();
msg2.what = 2;
h1.sendMessageDelayed(msg2, 2000);
};
}.start();
}
}
运行结果:
time:1500475211257; send msg thread: Thread-0
time:1500475211258; thread:handleThread; message what:1
time:1500475213258; thread:handleThread; message what:2
至此,我们已经用纯java的api实现了一个Android的Handler机制,如果你理解了上面所讲解的,那你也基本理解了Android的Handler机制
上面有的原生也都有,可以说原生就是上面的高级版本,增加了一些附加功能和重载一下api使得调用更方便。
下一节我就说说Android原生Handler机制与上面的例子(下文我们称为Demo)不同之处
Android原生Handler
1、Message类
原生Message比Demo中的提供了更丰富的功能主要体现在1.1、携带数据类型更多
/* 以下几个public参数就是用于使用者可以根据需求携带不同参数 */
public int what;
public int arg1;
public int arg2;
public Object obj;
/* 用于内部标记 */
int flags;
/* 用于使用者携带参数,通过get、set和peek方法 */
Bundle data;
/* 用于使用者携带处理方法,Handler的post(Runnable r)方法中的Runnable对象将被保存在这里 */
Runnable callback;
1.2、方法更丰富
提供出更多获取私有属性的方法和各种转换API1.3、消息增加回收处理
为了减少创建消息对象的次数,增加一个消息回收池(也是消息一个链表,保存着被回收的消息)主要代码如下:
/* 回收消息链表的同步锁对象 */
private static final Object sPoolSync = new Object();
/* 回收消息链表头 */
private static Message sPool;
/* 回收消息链表当前长度 */
private static int sPoolSize = 0;
/* 回收消息链表最大长度 */
private static final int MAX_POOL_SIZE = 50;
/* 获取消息的时候先去回收消息链表获取,有则返回没有再创建 */
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
sPoolSize--;
return m;
}
}
return new Message();
}
/* 释放消息的时候如果链表没达到允许最大值,则本消息加入到消息链表头 */
public void recycle() {
clearForRecycle();
synchronized (sPoolSync) {
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
2、MessageQueue类
这个类原生Message也是比Demo中的提供了更丰富的功能,除此之外有些功能的实现方式也有点不一样2.1、阻塞方式原生用本地方法实现
主要基于这几个方法实现阻塞和唤醒功能,我这里只是简单介绍一下,有兴趣同学可以自己去看看框架层源码 /* 初始化函数,返回一个唯一标志 */
private native static int nativeInit();
/* 释放底层对象 */
private native static void nativeDestroy(int ptr);
/* 阻塞函数(timeoutMillis <=0将不阻塞) */
private native static void nativePollOnce(int ptr, int timeoutMillis);
/* 唤醒函数 */
private native static void nativeWake(int ptr);
/* 判断是否空闲*/
private native static boolean nativeIsIdling(int ptr);
2.2、增加空闲处理
增加IdleHandler集合,当队列没有更多消息时,也就是将进入阻塞等待消息时,将依次回调该集合里面元素接口的方法IdleHandler是MessageQueue的一个静态内部接口,里面只有一个方法,源码如下:
public static interface IdleHandler {
/* 回调方法。返回值如果为true,这个IdleHandler将会继续生效(也就是下次队列进入阻塞的时候还会回调);
* 如果为false,这个IdleHandler将被移除 */
boolean queueIdle();
}
MessageQueue用一个数组维护着这个IdleHandler集合: private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
添加和移除IdleHandler方法: public void addIdleHandler(IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}
public void removeIdleHandler(IdleHandler handler) {
synchronized (this) {
mIdleHandlers.remove(handler);
}
}
2.3、增加同步分割栏
同步分割栏就是一种特殊的消息(这种Message的处理Handler也就是target属性为null),当它插入到消息队列,那么之后的同步消息将不会执行(异步消息可以执行),直到该同步消息分割栏被移除。同步消息和异步消息就是消息中的一个标志不同
用户发送的消息默认都是同步消息,发送异步消息、插入和移除同步分割栏API都被SDK隐藏了,若要使用此功能只能通过反射机制调用(后文会讲到)
该功能主要用于系统处理一些重要事情的时候可以先不处理用户发的消息。
插入和移除同步分割栏方法:
int enqueueSyncBarrier(long when) {
synchronized (this) {
/* 该标志作为分割栏唯一标志,移除时使用 */
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
/* 将唯一标志记录在arg1里面 */
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
/* 按when参数查找位置对应位置 */
while (p != null && p.when <= when) {
prev = p;
p = p.next;
}
}
/* 插入 */
if (prev != null) { // invariant: p == prev.next
msg.next = p;
prev.next = msg;
} else {
msg.next = p;
mMessages = msg;
}
return token;
}
}
/* 移除方法就是查找target为null并且arg1参数为token的消息,接着移除,
* 然后根据当前消息头消息判断是否需要唤醒,需要则进行唤醒 */
void removeSyncBarrier(int token) {
synchronized (this) {
Message prev = null;
Message p = mMessages;
while (p != null && (p.target != null || p.arg1 != token)) {
prev = p;
p = p.next;
}
if (p == null) {
throw new IllegalStateException("The specified message queue synchronization "
+ " barrier token has not been posted or has already been removed.");
}
final boolean needWake;
if (prev != null) {
prev.next = p.next;
needWake = false;
} else {
mMessages = p.next;
needWake = mMessages == null || mMessages.target != null;
}
p.recycle();
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
2.3、API更丰富
提供各种移除队列中未处理的消息,判断队列中是否存在目标消息,退出队列等方法获取下一条消息源码:
Message next() {
/* 记录将要处理的idleHandler的个数 */
int pendingIdleHandlerCount = -1; // -1 only during first iteration
/* 等待时间。-1:表示永远等待直到别人唤醒;0:表示不等待;其他数据表示等待时间。 */
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
/* 调用本地方法阻塞 */
nativePollOnce(mPtr, nextPollTimeoutMillis);
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
if (msg != null && msg.target == null) {
/* 队列头为同步分割栏,查找下一个异步消息 */
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;
msg.markInUse();
return msg;
}
} else {
/* 没有消息,等待直到别人唤醒(有消息插入将会唤醒) */
nextPollTimeoutMillis = -1;
}
if (mQuitting) {
dispose();
return null;
}
/* 没有消息需要处理,则处理IdleHandler */
if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
mBlocked = true;
continue;
}
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
/* 循环处理所有IdleHandler */
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("MessageQueue", "IdleHandler threw exception", t);
}
if (!keep) {
/* 回调返回false,移除该回调 */
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
插入消息源码:
基本和Demo一样我就不一一注释了
boolean enqueueMessage(Message msg, long when) {
if (msg.isInUse()) {
throw new AndroidRuntimeException(msg + " This message is already in use.");
}
if (msg.target == null) {
throw new AndroidRuntimeException("Message must have a target.");
}
synchronized (this) {
if (mQuitting) {
RuntimeException e = new RuntimeException( msg.target + " sending message to a Handler on a dead thread");
Log.w("MessageQueue", e.getMessage(), e);
return false;
}
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;
}
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}
移除消息源码:
void removeMessages(Handler h, int what, Object object) {
if (h == null) {
return;
}
synchronized (this) {
/* 如果队列头就是匹配消息则删除,并移动队列头 */
Message p = mMessages;
while (p != null && p.target == h && p.what == what && (object == null || p.obj == object)) {
Message n = p.next;
mMessages = n;
p.recycle();
p = n;
}
/* 队列头不是匹配消息,则遍历查找下一个,直到结尾 */
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.recycle();
p.next = nn;
continue;
}
}
p = n;
}
}
}
队列退出方法,等同于终止处理线程
参数:true的话将会处理完当前时刻以及之前的消息才会退出;false将直接清除所有消息并退出
源码:
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new RuntimeException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
nativeWake(mPtr);
}
}
其他源码读者自己去看
3、Handler类
原生的Handler类和Demo的Handler类功能一样,只是增加了很多获取消息和发送消息的重载方法,这些方法我就不多说了,我说说几个比较特别的功能3.1、消息处理机制多了
源码: public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
步骤:a、如果消息带有callback对象,则直接回调callback对象,完成处理;
b、如果消息没有callback对象,则判断Handler是否有全局callback对象,
有则回调(该回调具有boolean类型的返回值,true表示你已经处理了消息,不希望其他处理)
c、Handler没有全局callback对象,或者回调返回false,则调用Handler的handleMessage处理
3.2、增加任务同步运行
这个方法将会同步等待指定代码运行完成才会返回参数:r:将要运行的代码抽象
timeout:等待超时时间
public final boolean runWithScissors(final 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);
}
其中BlockingRunnable是Handler的一个私有内部静态类,利用Object的wait和notifyAll方法实现。步骤:
a、postAndWait将自己post到相应队列,相应队列已经退出返回false
b、然后等待利用wait方法阻塞等待
c、run方法运行,也就是处理线程处理了自己,就调用任务的run方法,然后通知wait唤醒
d、postAndWait返回true
源码如下:
private static final class BlockingRunnable implements Runnable {
private final Runnable mTask;
private boolean mDone;
public (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;
}
}
3.3、隐藏的功能
发送异步消息。上一节MessageQueue我们说到同步分割栏能阻塞该分割栏之后的同步消息,而异步消息则可以被处理,然后我还说用户默认发送的都是同步消息,那怎么样才能发送异步消息呢?我们就看看发送消息的源码:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
其中只有mAsynchronous 设置为true,才会发送异步消息,那我们看看mAsynchronous怎么样才会设置为true原来构造方法可以指定:
public Handler(Callback callback, boolean async) {
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
只是改构造方法被设置为@hide了,所以只能通过反射机制设置了4、Looper类
这个类基本一样,只是增加了几个api,具体读者自己去看。当然也增加了插入和移除同步分割栏的方法:
public int postSyncBarrier() {
return mQueue.enqueueSyncBarrier(SystemClock.uptimeMillis());
}
public void removeSyncBarrier(int token) {
mQueue.removeSyncBarrier(token);
}
这两个api也是@hide,所以也只能通过反射调用5、HandlerThread类
对于Demo中使用的LooperThread,Android原生也有一个,叫做HandlerThread,也就是帮你封装了一个Looper的Thread:public class HandlerThread extends Thread {
int mPriority;
int mTid = -1;
Looper mLooper;
public HandlerThread(String name) {
super(name);
mPriority = Process.THREAD_PRIORITY_DEFAULT;
}
public HandlerThread(String name, int priority) {
super(name);
mPriority = priority;
}
protected void onLooperPrepared() {
}
public void run() {
mTid = Process.myTid();
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Process.setThreadPriority(mPriority);
onLooperPrepared();
Looper.loop();
mTid = -1;
}
public Looper getLooper() {
if (!isAlive()) {
return null;
}
synchronized (this) {
while (isAlive() && mLooper == null) {
try {
wait();
} catch (InterruptedException e) {
}
}
}
return mLooper;
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
public boolean quitSafely() {
Looper looper = getLooper();
if (looper != null) {
looper.quitSafely();
return true;
}
return false;
}
public int getThreadId() {
return mTid;
}
}
到这里我们已经将Android的Handler机制和源码都讲完了,不知道小伙伴是否理解了呢?
上一篇: 【php安装与配置】安装前需要考虑的事项
下一篇: 2017最新PHP经典面试题目汇总
推荐阅读
-
android编程之XML文件解析方法详解(附源码)
-
android的消息处理机制(图文+源码分析)—Looper/Handler/Message
-
android线程消息机制之Handler详解
-
Android事件分发机制源码解析
-
Android消息处理机制Looper和Handler详解
-
Handler异步消息传递机制(四)Handler发送消息流程,源码(Android 9.0)彻底解析
-
Android消息通信机制Handler详解,Handler,Looper,MessageQueue,源码解析,讲解这几个类怎么配合工作的
-
Android消息机制三剑客之Handler、Looper、Message源码分析(一)
-
Android消息机制原理,仿写Handler Looper源码解析跨线程通信原理--之仿写模拟Handler(四)
-
Android Handler机制(三)----Looper源码解析