一、Handler总览
Handler
是Android
消息处理机制的上层接口。
Android
消息处理机制本质:一个线程不断地从消息队列中获取消息,并进行处理的机制
Handler
主要应用场景:在子线程中进行一些耗时的I/O
操作,操作完毕后需要在主线程更新UI
,使用Handler
将UI
更新操作切换到主线程执行。
看一下Handler
内的几个核心角色:
-
Message:
消息的载体。包含消息ID,消息处理对象以及处理的数据等,由
MessageQueue
统一列队,终由Handler
处理 -
Handler:
发送消息的工具类,用于发送和处理消息
-
MessageQueue
:存储
Handler
发送过来的Message
,内部维护了Message
链表,同时也是与native
通信的中枢。每次拿取
Message
时,若该Message
离真正执行还需要一段时间,会通过nativePollOnce
进入阻塞状态,避免资源的浪费。若存在消息屏障,则会忽略同步消息优先拿取异步消息,从而实现异步消息的优先消费。 -
Looper
:一个用于遍历
MessageQueue
的类。每个线程有一个独有的Looper
,在所处线程开启一个死循环,不断从MessageQueue
中获取Message
,然后交给Handler
处理 -
Messenger:
可以跨进程传输的消息载体 -
......
总览一下Handler的整体架构设计图
APP
内可运行多个线程,不同线程间可以互相拿到对方的Handler
对象MessageQueue
与native
通信,native
与kernel
通信,此调用链赋予了App
使用系统内核资源的能力- 一个线程有多个
Handler
,只能有一个Looper
,一个Looper
对象拥有一个MessageQueue
看一下Handler
的消息处理机制流程
Handler
的消息处理机制流程基本是:
- 在
handler
所创建的线程需要维护一个唯一的Looper
对象, 一个线程只能有一个Looper
,每个线程的Looper
通过ThreadLocal
来保证。 Looper
对象的内部又维护有唯一的一个MessageQueue
。所以一个线程可以有多个handler
,但是只能有一个Looper
和一个MessageQueue
Message
在MessageQueue
不是通过一个列表来存储的,而是将传入的Message
存入到了上一个Message
的next
中,在取出的时候通过顶部的Message
就能按放入的顺序依次取出Message
Looper
对象通过loop()
方法开启了一个死循环,不断地从looper
内的MessageQueue
中取出Message
,然后通过handler
将消息分发传回handler
所在的线程
二、基本使用
看一下Handler
的消息处理的分发函数dispatchMessage
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
从dispatchMessage
可知,Handler
的使用分为handleCallback()
、mCallback.handleMessage()
和handleMessage()
2.1 handleCallback
handleCallback()
可以理解为收发一体,消息的发送和接收都在post()
中完成,无需创建Message
实例
class MainActivity : AppCompatActivity(){
private lateinit var mMsgTv:TextView
private val mHandler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mMsgTv = findViewById(R.id.handler_demo)
thread {
val info = "子线程处理结果"
mHandler.post {
mMsgTv.text = info //UI更新
}
}
}
}
2.2 handleMessage
handleMessage
又分为mCallback.handleMessage()
与handleMessage()
mCallback.handleMessage()
使用
实现callback
接口即可
class MainActivity : AppCompatActivity(){
private lateinit var mMsgTv:TextView
//接收消息,刷新UI
private val mHandler = Handler(Looper.getMainLooper()) { msg ->
if (msg.what == 1) {
mMsgTv.text = msg.obj.toString()
}
//返回false 重写Handler类的handleMessage会被调用;返回true 则不会被调用
return@Handler false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mMsgTv = findViewById(R.id.handler_demo)
//子线程中发送消息
thread {
val message = Message.obtain()
message.what = 1
message.obj = "者文个人博客:https://zhewendev.github.io/"
mHandler.sendMessage(message)
}
}
}
handleMessage()
使用
重写Handler
类的handlerMessage()
方法
class MainActivity : AppCompatActivity(){
private lateinit var mMsgTv:TextView
//接收消息,刷新UI
private val mHandler = object :Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
if (msg.what == 1) {
mMsgTv.text = msg.obj.toString()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mMsgTv = findViewById(R.id.handler_demo)
//子线程中发送消息
thread {
val message = Message.obtain()
message.what = 1
message.obj = "者文微信公众号:者文静斋"
mHandler.sendMessage(message)
}
}
}
下面看一下Handler
的内部实现
三、Looper
实际开发中,若遇到子线程与子线程通信,在子线程初始化Handler
时,需
thread {
Looper.prepare()
val handler = Looper.myLooper()?.let { Handler(it) }
Looper.loop()
}
主线程初始化Handler
时怎么不需要做Looper.prepare()
等处理呢,看一下主线程入口
ActivityThread.java
...
public static void main(String[] args) {
...
//主线程Looper
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
//主线程的loop开始循环
Looper.loop();
...
}
//Looper.java
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
...
主线程在Looper.prepareMainLooper()
中创建了主线程的Looper
,并调用了loop
方法,所以可以直接使用Handler
prepare
和loop
作用
为什么要使用prepare
和loop
呢
Looper.prepare()
:生成Looper
对象,set
在ThreadLocal
里handler
构造函数:通过Looper.myLooper()
获取到ThreadLocal
的Looper
对象Looper.loop()
:内部有个死循环,开始事件分发
prepare()
实现
看一下prepare()
//Looper.java
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");
}
//将new出来的Looper实例设置给sThreadLocal
sThreadLocal.set(new Looper(quitAllowed));
}
Looper.prepare()
会生成Looper
对象,set
在ThreadLocal
里。一个线程内只能使用一次prepare()
,否则会抛异常
loop()
实现
Looper
创建好后,不会自己启动,需要手动启动,调用loop()
函数即可。创建Looper并开启消息循环,Looper
的prepare
和loop
方法是配套使用的,两者必须成对存在。
public static void loop() {
//获取当前线程的Looper
final Looper me = myLooper();
......
//开启死循环读取消息
for (;;) {
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
Message msg = me.mQueue.next(); // might block
.....
try {
//调用Message对应的handler处理消息
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
}
......
//回收Message
msg.recycleUnchecked();
return true;
}
Looper.loop()
主要实现内容:
- 获取当前线程的
Looper
对象和MessageQueue
,开启死循环读取消息 - 通过
dispatchMessage
方法把消息分发下去 - 消息回收,放回到消息缓存池。
这里需要注意的是 Message
对象并没有释放,会缓存起来
Looper
小结:
Looper
会不断从MessageQueue
中获取消息,然后交给Handler
去处理。Looper
使用前需要先初始化当前线程的Looper
对象,再调用loop()
方法来启动它
Handler
是线程切换的核心,因为不同的Looper
运行在不同的线程,其调用的dispatchMessage
方法则运行在不同的线程,因此Message
的处理就被切换到Looper
所在的线程了。
当looper
不再使用时,可调用不同的退出方法来退出他。Looper
一旦退出,线程则会直接结束。
四、消息收发
看一下Message
的数据结构
public final class Message implements Parcelable {
public int what;
public int arg1;
public int arg2;
public Object obj;
public long when;
Message next;
Handler target;
......
}
其中target
是Handler
类型,表示该Message
归属的Handler
,会在Handler
发送消息时赋值。
先看一下Message
中when
这个属性,这是内部包才能访问的写操作,将消息加入到消息队列的时候会给发送的消息设置该属性。
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
再继续追溯下去,发现when = SystemClock.uptimeMillis() + delayMillis
使用sendMessage
发送消息的时候,实际上也会调用sendMessageDelayed
延时发送消息发放,不过此时传入的延时时间会默认为0
4.1 发送消息
消息的发送形式有两种:sendMessage()
和post()
,对于post()
,其Runnable
会被封装进一个Message
,所以它本质上还是一个Message
Handler
发送消息,不管使用哪种形式,都会调用到Handler
的enqueueMessage()
方法中,最终调用到MessageQueue
的enqueueMessage()
中
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
post()
和sendMessage()
都通过sendMessageDelayed()
进行消息发送,再继续跟踪
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
......
return enqueueMessage(queue, msg, uptimeMillis);
}
//Handler.java
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
//将当前的Handler赋值给Message的target属性
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
//设置为异步方法
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
Handler
发送消息,调用到Handler
的enqueueMessage()
方法中,将当前Handler
赋值给Message
的when
,最后调用到MessageQueue
的enqueueMessage
方法
MessageQueue/enqueueMessage()
方法
boolean enqueueMessage(Message msg, long when) {
//Handler为空,抛出异常
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
//对MessageQueue进行加锁
synchronized (this) {
//当前消息如果已经被执行,抛出异常
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
//判断目标Thread是否已死亡
if (mQuitting) {
......
msg.recycle();
return false;
}
//标记Message正在被执行,以及需要被执行的时间。
msg.markInUse();
msg.when = when;
Message p = mMessages; //P是messageQueue的链表头
boolean needWake; // 判断是否需要唤醒MessageQueue
// 如果有新的队头,同时MessageQueue处于阻塞状态则需要唤醒队列
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;
}
MessageQueue
的enqueueMessage()
主要内容是:
- 首先判断
Message
中的Handler
不能为空,且Message
不能为在使用中,否则抛异常 - 对
MessageQueue
进行加锁,判断当前线程是否dead
,dead
就抛异常 - 标记
Message
的执行时间等 - 新插入的
Message
在链表头时,如果messageQueue
是空的或者正在等待下个延迟消息,则需要唤醒MessageQueue
- 根据
Message
的执行时间,找到在链表中的插入位置进行插入,这里我们可以理解MessageQueue
中维护了一个优先级队列
4.2 分发消息
Handler
发送的消息放入了MessageQueue
中,接着进入消息的读取与分发了。
Looper
的Loop
方法会从MessageQueue
中循环读取消息,调用queue.next()
MessageQueue/next()
实现
Message next() {
// Return here if the message loop has already quit and been disposed.
// 源码中的注释表示:如果looper已经退出了,这里就返回null
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
int nextPollTimeoutMillis = 0; // 定义阻塞时间赋值为0
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
// 阻塞对应时间 这个方法最终会调用到linux的epoll机制
nativePollOnce(ptr, nextPollTimeoutMillis);
// 对MessageQueue进行加锁,保证线程安全
synchronized (this) {
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//...
if (msg != null) {
if (now < msg.when) {
// 下一个消息还没开始,等待两者的时间差
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 获得消息且现在要执行,标记MessageQueue为非阻塞
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;
}
//...
}
}
MessageQueue/next()
目的:
- 获取
MessageQueue
中的一个Message
,进行死循环读取。 - 如果消息队列中没有消息,那么
next
方法会一直阻塞在这里。 - 当有新消息到来时,就会将它唤醒,
next
方法会返回这条消息并将其从优先级队列中给移除。
获取到消息后,进行消息的分发,即msg.target.dispatchMessage(msg)
消息池
loopOnce
代码尾部执行了msg.recycleUnchecked()
,这是将完成分发的消息放入消息池,等待被复用。有存入消息池操作,肯定有取出操作。
当我们获取Message
的时候,官方建议是通过Message.obtain()
方法来获取,看一下该方法
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();
}
Message
维护了一个静态链表,链表头是sPool
,Message
有一个next
属性,Message
本身就是链表结构。
sPoolSync
是一个object
对象,仅作为解决并发访问安全设计。当我们调用obtain
来获取一个新的Message
的时候,首先会检查链表中是否有空闲的Message
,如果没有则新建一个返回。
看一下msg.recycleUnchecked()
void recycleUnchecked() {
// Clear out all other details.
//相关属性全部重置
flags = FLAG_IN_USE;
what = 0;
arg1 = 0;
arg2 = 0;
obj = null;
replyTo = null;
sendingUid = UID_NONE;
workSourceUid = UID_NONE;
when = 0;
target = null;
callback = null;
data = null;
//存入消息池
synchronized (sPoolSync) {
//判断是否超出消息池的最大容量
if (sPoolSize < MAX_POOL_SIZE) {
next = sPool;
sPool = this;
sPoolSize++;
}
}
}
Message
使用完成后,可以调用Message
的recycle
方法进行回收。把Message
中的内容清空,然后判断链表是否达到最大值(50
),然后插入消息池的链表中。
4.3 接收消息
直接看一下dispatchMessage()
实现
Handler.java
...
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
...
五、同步屏障
Handler
发送的Message
会放入到MessageQueue
中,MessageQueue
中维护了一个优先级队列,将存储数据的单链表按照时间升序进行排序,Looper
则按照顺序,每次从这个优先级队列中取出一个Message
进行分发,一个处理完就处理下一个。
是否可以让指定的Message
优先被处理?当然可以,即通过同步屏障实现。
看一下MessageQueue.next()
中部分关键代码
Message next() {
//...
for (;;) {
synchronized (this) {
if (msg != null && msg.target == null) {
// 存在同步屏障,寻找队列中下一个同步屏障消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
}
}
msg.target
什么时候会为空?怎么判断是异步消息?
看一下Handler
的enqueueMessage()
方法
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
//将当前的Handler赋值给target
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
通过Handler
的post
和send
系列方法都会走到这个方法内,msg.target
会被赋值,不可能为空。说明是其他消息发送的方法导致的。
5.1 同步屏障消息生成
看一下MessageQueue
的postSyncBarrier
public int postSyncBarrier() {
return postSyncBarrier(SystemClock.uptimeMillis());
}
//Message target属性为null的消息插入
private int postSyncBarrier(long when) {
// Enqueue a new sync barrier token.
// We don't need to wake the queue because the purpose of a barrier is to stall it.
synchronized (this) {
final int token = mNextBarrierToken++;
final Message msg = Message.obtain();
msg.markInUse();
msg.when = when;
msg.arg1 = token;
Message prev = null;
Message p = mMessages;
if (when != 0) {
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;
}
}
Message
的target
属性为null
就是同步屏障。这是一种特殊消息,不会被消费,仅作为一个标识处于MessageQueue
中。当MessageQueue
的next
方法遇到同步屏障的时,会循环遍历整个链表找到标记为异步消息的Message
,忽略其他消息,则异步消息就被提前执行了。
异步消息处理完,同步屏障不会被移除,需要手动移除。若不移除,同步消息永远无法执行。
public void removeSyncBarrier(int token) {
// Remove a sync barrier token from the queue.
// If the queue is no longer stalled by a barrier then wake it.
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.recycleUnchecked();
// If the loop is quitting then it is already awake.
// We can assume mPtr != 0 when mQuitting is false.
if (needWake && !mQuitting) {
nativeWake(mPtr);
}
}
}
5.2 异步消息生成
如何生成一个异步消息?看一下Handler
的enqueueMessage()
方法
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
//如果mAsynchronous,将消息设置为异步消息
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
通过msg.setAsynchronous
方法设置为true
,可以把一个消息变成异步消息,但是前提得满足mAsynchronous
属性为true
。
mAsynchronous
是Handler
中的一个属性,会在这两个构造方法中被赋值
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
//...
mAsynchronous = async;
}
public Handler(@Nullable Callback callback, boolean async) {
//...
mAsynchronous = async;
}
前述的两个构造方法都是对外不可见的,无法调用,且设置同步屏障的方法对外也是不可见,只能系统会去使用它。
例如在ViewRootImpl
中执行UI
绘制的方法会使用到同步屏障:
ViewRootImpl.java
...
void scheduleTraversals() {
if (!mTraversalScheduled) {
mTraversalScheduled = true;
mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
mChoreographer.postCallback(
Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
notifyRendererOfFramePending();
pokeDrawLockIfNeeded();
}
}
在把绘制消息放入队列之前,先放入了一个同步屏障,然后再发送异步绘制消息,从而使得界面绘制的消息会比其他消息优先执行,避免了因为 MessageQueue
中消息太多导致绘制消息被阻塞导致画面卡顿。当绘制完成后,就会将同步屏障移除。
六、IdleHandler
IdleHandle
是MessageQueue
中的一个静态内部接口,当消息队列没有消息时或者是队列中的消息还没有到执行时间时才会执行的 IdleHandler
,它存放在 mPendingIdleHandlers
队列中。
public static interface IdleHandler {
boolean queueIdle();
}
IdleHandle
常见应用场景:在UI
线程处理完所有View
事务后,处于空闲状态时会回调该接口进行一些额外操作,且不会阻塞主线程。
6.1 基本使用
class MainActivity : AppCompatActivity(){
companion object {
const val TAG = "MainActivity"
}
private val mHandler = object :Handler(Looper.getMainLooper()) {
override fun handleMessage(msg: Message) {
super.handleMessage(msg)
if (msg.what == 2 || msg.what == 3) {
Log.d(TAG, msg.obj.toString())
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
testIdleHandler()
}
fun testIdleHandler() {
Looper.myQueue().addIdleHandler {
Toast.makeText(this@MainActivity,"消息空闲时发个Toast",Toast.LENGTH_SHORT).show()
Log.d(TAG,"来自IdleHandler 的空闲消息")
return@addIdleHandler false
}
val message = Message.obtain()
message.what = 2
message.obj = "来自Handler 的消息"
mHandler.sendMessage(message)
val message1 = Message.obtain()
message1.what = 3
message1.obj = "来自Handler 的第二条消息"
mHandler.sendMessage(message1)
}
}
/******打印结果******/
来自Handler 的消息
来自Handler 的第二条消息
来自IdleHandler 的空闲消息
IdleHandler
在消息队列其它消息执行完后才执行,且只执行一次。如果前述示例addIdleHandle
操作时返回true
,则会多次执行,只要空闲就会一直执行,不会从 IdleHandler
的队列中删除。
6.2 原理解析
看一下addIdleHandler()
的内部实现
public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
//添加进mIdleHandlers队列中
mIdleHandlers.add(handler);
}
}
看一下MessageQueue
的next
关于IdleHandler
的部分内容
Message next() {
int pendingIdleHandlerCount = -1;
for(;;) {
synchronized (this) {
//当前无消息,或还需要等待一段时间消息才能分发,获得IdleHandler的数量
if (pendingIdleHandlerCount < 0 && (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
//如果没有idle handler需要执行,阻塞线程进入下次循环
mBlocked = true;
continue;
}
//初始化mPendingIdleHandlers
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
//把List转化成数组类型
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 {
//获得idler.queueIdle的返回值
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
//keep即idler.queueIdle的返回值,如果为false表明只要执行一次,并移除,否则不移除
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
//将pendingIdleHandlerCount置为0避免下次再次执行
pendingIdleHandlerCount = 0;
// 当在执行IdleHandler的时候,可能有新的消息已经进来了
// 所以这个时候不能阻塞,要回去循环一次看一下
nextPollTimeoutMillis = 0;
}
}
MessageQueue.next()
中关于IdleHandler
的主要内容:
- 初始时,将
pendingIdleHandlerCount
赋值为-1 - 判断
pendingIdleHandlerCount
是否小于0并且MessageQueue
是否为空或者有延迟消息需要执行。如果是则把存储IdleHandler
的list
的长度赋值给pendingIdleHandlerCount
- 判断如果没有
IdleHandler
需要执行,阻塞线程进入下次循环。如果有,则初始化mPendingIdleHandlers
,把list
中的所有IdleHandler
放到数组中。这一步是为了不让在执行IdleHandler
的时候List
被插入新的IdleHandler
,造成逻辑混乱 - 循环遍历所有的
IdleHandler
并执行,查看idler.queueIdle
方法的返回值。为false
表明这个IdleHandler
只需要执行一次,并移除;为true
,则不移除 - 将
pendingIdleHandlerCount
置为0避免下次再次执行。当在执行IdleHandler
的时候,可能有新的消息已经进来了,所以这个时候不能阻塞,要回去循环一次看一下
七、Handler典型应用
7.1 Looper妙用
可以通过Looper.getMainLooper
方法获取主线程Looper
,从而可以判断当前线程是否是主线程
可以通过Handler
将Runnable
post
到主线程执行
object MainThread {
private val HANDLER = Handler(Looper.getMainLooper())
fun run(runnable: Runnable) {
if (isMainThread) {
runnable.run()
} else {
HANDLER.post(runnable)
}
}
val isMainThread: Boolean
get() = Looper.myLooper() == Looper.getMainLooper()
}
7.2 HandlerThread
主线程发送消息到子线程处理,可以用HandlerThread
,其继承了Thread
并对Looper
进行了封装。
class MainActivity : AppCompatActivity(){
companion object {
const val TAG = "MainActivity"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
testHandlerThread()
}
fun testHandlerThread() {
//1,创建HandlerThread实例
val mHandlerThread = HandlerThread("HandlerThread")
//2,启动线程
mHandlerThread.start()
//3,使用传入Looper为参数的构造方法创建Handler实例
val handler: Handler = object : Handler(mHandlerThread.looper) {
override fun handleMessage(msg: Message) {
Log.d(TAG, "当前线程: " + Thread.currentThread().name + " handleMessage")
}
}
//4,使用Handler发送消息
handler.sendEmptyMessage(0x001)
//5 在合适的时机调用HandlerThread的quit方法,退出消息循环
}
}
Handler
、HandlerThread
、Thread
三者区别:
Handler
:在Android中负责发送和处理消息HandlerThread
:继承自Thread
,对Looper
进行了封装,也就是说它在子线程维护了一个Looper
,方便我们在子线程中去处理消息Thread
:cpu执行的最小单位,即线程,它在执行完后就立马结束了,并不能去处理消息。如果要处理,需要配合Looper
,Handler
一起使用
7.3 子线程处理Toast、Dialog
fun testToast() {
thread {
Toast.makeText(this@MainActivity,"子线程弹Toast",Toast.LENGTH_SHORT).show()
}
}
上述代码运行会崩溃
java.lang.NullPointerException: Can't toast on a thread that has not called Looper.prepare()
Toast
的实现依赖Handler
,在子线程中创建Handler
,需先创建Looper
并开启消息循环
private fun testToast() {
thread {
Looper.prepare()
Toast.makeText(this@MainActivity,"子线程弹Toast",Toast.LENGTH_SHORT).show()
Looper.loop()
}
}
Dialog
与Toast
类似,其实现也依赖Handler
。