- Handler
- MessageQueue
- Looper
- loop(): 循环取出messagequeue消息队列中的消息,并分发出去。再把分发后的Message回收到消息池,以便重复利用
- myLooper(): 获取当前 Looper
- myQueue(): 获取当前 MessageQueue
- prepare(): 创建 Looper, 用于在子线程创建子线程的 Looper
- getMainLooper(): 获取主线程 Looper
- getThread(): 获取当前线程
- isCurrentThread(): 判断是否是当前线程
- quit()/quitSafely(): 两者区别在于 quit 会回收所有 Message, quitSafely 只会回收当前时间后的 Message
- Message
Handler
什么是 Handler
Handler 是 Android 消息处理机制中负责发送消息和处理消息的环节
Handler 主要有两个用途:
- 计划
Message和Runable在将来的某个时刻执行 - 在与您自己的线程不同的线程上发送消息
Handler 使用方式
Handler 的构造方法里 Handler() 不推荐使用, 在 Handler 构建期间隐式选择 Looper 可能会导致以下错误:运行时会静默丢失操作(如果 Handler 不期望新任务并退出),崩溃(如果在没有 Looper 处于活动状态的线程上创建了 Handler )或竞争条件, Handler 与之关联的线程不在作者预期的范围内
推荐使用指定 Looper 的构造方法 Handler(Looper looper)
val handler: Handler = object : Handler(Looper.getMainLooper()){// 处理已发送的消息override fun handleMessage(msg: Message) {super.handleMessage(msg)println(">>>>> Handler:" + Thread.currentThread().name)}}// 发送空消息handler.sendEmptyMessage(0)// 发送消息handler.sendMessage(message)handler.post {// Runnable 代替了 handleMessage 来直接处理此次 Runnable 消息// 此方式在子线程有些用途, 在主线程就显得多次一举}/*** 子线程创建 Handler*/var handler: Handler? = nullval thread = object : Thread("ThreadA") {override fun run() {super.run()Looper.prepare()handler = object : Handler(Looper.myLooper()) {override fun handleMessage(msg: Message) {super.handleMessage(msg)println(msg.toString())}}Looper.loop()}}thread.start()/*** 通过 HandlerThread 创建 Handler*/val handlerThread: HandlerThread = HandlerThread("HandlerThread")handlerThread.start()val handler: Handler = object : Handler(handlerThread.looper){override fun handleMessage(msg: Message) {super.handleMessage(msg)println(">>>>> Handler:" + Thread.currentThread().name)}}
Handler 解析
Handler 的 send 和 post 系列方法的实质
Handler 的 send 和 post 系列方法最后都是把数据封装到了 Message 内
Handler 的 send 和 post 系列方法的实质实际上都是调用了 sendMessageAtTime(Message msg, long uptimeMillis) , 通过 uptimeMillis 来对消息队列进行排序.uptimeMillis = SystemClock.uptimeMillis() + delayMillis , 设备开机到现在的时间 + 延迟时间
Handler#dispatchMessage(Message)
Looper将 Message 对象从 MessageQueue 中取出来,并将其交给 Handler#dispatchMessage(Message) 方法而不是交给 Handler#handleMessage(Message) , 从源码里就可以看出:
public void dispatchMessage(@NonNull Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);}}
参考链接
https://www.jianshu.com/p/f70ee1765a61
https://blog.csdn.net/qq_37321098/article/details/81535449
MessageQueue
MessageQueue 消息队列, 用于储存 Message. Message 添加到消息队列时会先判断队列里是否还有 Message, 若没有则直接添加队列, 若有则对其根据 when 进行排序后添加到队列
注: 消息队列为后进先出
添加消息到队列
队列中的Message触发时间是有先后顺序的。当消息加入消息队列时,会从队列头开始遍历,直到找到消息应该插入的合适位置,以保证所有消息的时间顺序(内部遍历队列中Message,找到when比当前Message的when大的Message,将Message插入到该Message之前,如果没找到则将Message插入到队列最后)。一般是当前队列为空的情况下,next那边会进入睡眠,需要的时候MessageQueue这边会唤醒 next() 方法
/*** 通过 Handler 将消息添加到队列*/boolean enqueueMessage(Message msg, long when) {// 每一个普通Message必须有一个target-handlerif (msg.target == null) {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) {msg.recycle();return false;}//标记使用状态,记录执行时间msg.markInUse();msg.when = when;Message p = mMessages;boolean needWake;//p为null代表MessageQueue没有消息或者msg的触发时间是队列中最早的if (p == null || when == 0 || when < p.when) {msg.next = p;mMessages = msg;needWake = mBlocked; //当阻塞时需要唤醒} else {//将消息按时间顺序插入到MessageQueue。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;prev.next = msg;}if (needWake) {nativeWake(mPtr);}}return true;}————————————————版权声明:本文为CSDN博主「魔法少女 厄加特」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_37321098/article/details/81535449
取出消息
next() 方法中,做了异步Message消息的判断, 特殊的是这个Message没有设置target,即 msg.target 为null
//不停提取下一条messageMessage next() {final long ptr = mPtr;//判断是否退出消息循环if (ptr == 0) {return null;}int pendingIdleHandlerCount = -1;//代表下一个消息到来前,还需要等待的时长int nextPollTimeoutMillis = 0;for (;;) {if (nextPollTimeoutMillis != 0) {Binder.flushPendingCommands();}//native层阻塞cpu。如果被阻塞,唤醒事件队列nativePollOnce(ptr, nextPollTimeoutMillis);synchronized (this) {final long now = SystemClock.uptimeMillis();Message prevMsg = null;Message msg = mMessages;//如果当前消息是异步消息,都将赋值给prevMsg,过滤掉,直到取到了非异步消息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;//设置消息的使用状态,即flags |= FLAG_IN_USEmsg.markInUse();return msg; //成功地获取MessageQueue中的下一条即将要执行的消息}} else {//表示消息队列中无消息,会一直等待下去nextPollTimeoutMillis = -1;}......//IdleHandler为发现线程何时阻塞的回调接口for (int i = 0; i < pendingIdleHandlerCount; i++) {final IdleHandler idler = mPendingIdleHandlers[i];mPendingIdleHandlers[i] = null; //去除handler引用boolean keep = false;//queueIdle返回true会被空闲的处理器处理,false就会被移走try {keep = idler.queueIdle(); //idle时执行的方法} catch (Throwable t) {Log.wtf(TAG, "IdleHandler threw exception", t);}if (!keep) {synchronized (this) {mIdleHandlers.remove(idler); //被移走}}}//重置idle handler个数为0,保证不会再次重复运行pendingIdleHandlerCount = 0;nextPollTimeoutMillis = 0;}}————————————————版权声明:本文为CSDN博主「魔法少女 厄加特」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_37321098/article/details/81535449
移除消息
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.recycleUnchecked();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.recycleUnchecked();p.next = nn;continue;}}p = n;}}}void removeCallbacksAndMessages(Handler h, Object object) {if (h == null) {return;}synchronized (this) {Message p = mMessages;while (p != null && p.target == h&& (object == null || p.obj == object)) {Message n = p.next;mMessages = n;p.recycleUnchecked();p = n;}while (p != null) {Message n = p.next;if (n != null) {if (n.target == h && (object == null || n.obj == object)) {Message nn = n.next;n.recycleUnchecked();p.next = nn;continue;}}p = n;}}}
参考链接
https://blog.csdn.net/qq_37321098/article/details/81535449
Looper
用于为线程运行消息循环的类。默认情况下,线程没有与之关联的消息循环。若要创建一个,请prepare()在要运行循环的线程中进行调用 ,然后 loop()让其处理消息,直到循环停止为止
与消息循环的大多数交互是通过 Handler 类进行的
作用: 负责读取MessageQueen中的消息,读到消息之后就把消息交给Handler去处理
loop(): 循环取出messagequeue消息队列中的消息,并分发出去。再把分发后的Message回收到消息池,以便重复利用
myLooper(): 获取当前 Looper
myQueue(): 获取当前 MessageQueue
prepare(): 创建 Looper, 用于在子线程创建子线程的 Looper
getMainLooper(): 获取主线程 Looper
getThread(): 获取当前线程
isCurrentThread(): 判断是否是当前线程
quit()/quitSafely(): 两者区别在于 quit 会回收所有 Message, quitSafely 只会回收当前时间后的 Message
Message
创建 Message
// 创建 Messageval message = Message.obtain()val message = handler.obtainMessage()
Message 解析
/*** 用于分类 Message 的类型*/public int what;/*** 如果您只需要存储几个整数值,那么arg1和arg2是使用* {@link #setData(Bundle) setData()}的较低成本的替代方法*/public int arg1;/*** 如果您只需要存储几个整数值,那么arg1和arg2是使用* {@link #setData(Bundle) setData()}的较低成本的替代方法*/public int arg2;/*** 要发送给收件人的任意对象*/public Object obj;/*** 传递 Messenger, 用于通过 Messenger 回复消息*/public Messenger replyTo;
