Handler

什么是 Handler

Handler 是 Android 消息处理机制中负责发送消息和处理消息的环节
Handler 主要有两个用途:

  1. 计划 MessageRunable 在将来的某个时刻执行
  2. 在与您自己的线程不同的线程上发送消息

Handler 使用方式

Handler 的构造方法里 Handler() 不推荐使用, 在 Handler 构建期间隐式选择 Looper 可能会导致以下错误:运行时会静默丢失操作(如果 Handler 不期望新任务并退出),崩溃(如果在没有 Looper 处于活动状态的线程上创建了 Handler )或竞争条件, Handler 与之关联的线程不在作者预期的范围内

推荐使用指定 Looper 的构造方法 Handler(Looper looper)

  1. val handler: Handler = object : Handler(Looper.getMainLooper()){
  2. // 处理已发送的消息
  3. override fun handleMessage(msg: Message) {
  4. super.handleMessage(msg)
  5. println(">>>>> Handler:" + Thread.currentThread().name)
  6. }
  7. }
  8. // 发送空消息
  9. handler.sendEmptyMessage(0)
  10. // 发送消息
  11. handler.sendMessage(message)
  12. handler.post {
  13. // Runnable 代替了 handleMessage 来直接处理此次 Runnable 消息
  14. // 此方式在子线程有些用途, 在主线程就显得多次一举
  15. }
  16. /**
  17. * 子线程创建 Handler
  18. */
  19. var handler: Handler? = null
  20. val thread = object : Thread("ThreadA") {
  21. override fun run() {
  22. super.run()
  23. Looper.prepare()
  24. handler = object : Handler(Looper.myLooper()) {
  25. override fun handleMessage(msg: Message) {
  26. super.handleMessage(msg)
  27. println(msg.toString())
  28. }
  29. }
  30. Looper.loop()
  31. }
  32. }
  33. thread.start()
  34. /**
  35. * 通过 HandlerThread 创建 Handler
  36. */
  37. val handlerThread: HandlerThread = HandlerThread("HandlerThread")
  38. handlerThread.start()
  39. val handler: Handler = object : Handler(handlerThread.looper){
  40. override fun handleMessage(msg: Message) {
  41. super.handleMessage(msg)
  42. println(">>>>> Handler:" + Thread.currentThread().name)
  43. }
  44. }

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) , 从源码里就可以看出:

  1. public void dispatchMessage(@NonNull Message msg) {
  2. if (msg.callback != null) {
  3. handleCallback(msg);
  4. } else {
  5. if (mCallback != null) {
  6. if (mCallback.handleMessage(msg)) {
  7. return;
  8. }
  9. }
  10. handleMessage(msg);
  11. }
  12. }

参考链接

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() 方法

  1. /**
  2. * 通过 Handler 将消息添加到队列
  3. */
  4. boolean enqueueMessage(Message msg, long when) {
  5. // 每一个普通Message必须有一个target-handler
  6. if (msg.target == null) {
  7. throw new IllegalArgumentException("Message must have a target.");
  8. }
  9. //已在使用状态
  10. if (msg.isInUse()) {
  11. throw new IllegalStateException(msg + " This message is already in use.");
  12. }
  13. synchronized (this) {
  14. //消息在退出状态->被回收到消息池
  15. if (mQuitting) {
  16. msg.recycle();
  17. return false;
  18. }
  19. //标记使用状态,记录执行时间
  20. msg.markInUse();
  21. msg.when = when;
  22. Message p = mMessages;
  23. boolean needWake;
  24. //p为null代表MessageQueue没有消息或者msg的触发时间是队列中最早的
  25. if (p == null || when == 0 || when < p.when) {
  26. msg.next = p;
  27. mMessages = msg;
  28. needWake = mBlocked; //当阻塞时需要唤醒
  29. } else {
  30. //将消息按时间顺序插入到MessageQueue。
  31. needWake = mBlocked && p.target == null && msg.isAsynchronous();
  32. Message prev;
  33. for (;;) {
  34. prev = p;
  35. p = p.next;
  36. if (p == null || when < p.when) {
  37. break;
  38. }
  39. if (needWake && p.isAsynchronous()) {
  40. needWake = false;
  41. }
  42. }
  43. msg.next = p;
  44. prev.next = msg;
  45. }
  46. if (needWake) {
  47. nativeWake(mPtr);
  48. }
  49. }
  50. return true;
  51. }
  52. ————————————————
  53. 版权声明:本文为CSDN博主「魔法少女 厄加特」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
  54. 原文链接:https://blog.csdn.net/qq_37321098/article/details/81535449

取出消息

next() 方法中,做了异步Message消息的判断, 特殊的是这个Message没有设置target,即 msg.target 为null

  1. //不停提取下一条message
  2. Message next() {
  3. final long ptr = mPtr;
  4. //判断是否退出消息循环
  5. if (ptr == 0) {
  6. return null;
  7. }
  8. int pendingIdleHandlerCount = -1;
  9. //代表下一个消息到来前,还需要等待的时长
  10. int nextPollTimeoutMillis = 0;
  11. for (;;) {
  12. if (nextPollTimeoutMillis != 0) {
  13. Binder.flushPendingCommands();
  14. }
  15. //native层阻塞cpu。如果被阻塞,唤醒事件队列
  16. nativePollOnce(ptr, nextPollTimeoutMillis);
  17. synchronized (this) {
  18. final long now = SystemClock.uptimeMillis();
  19. Message prevMsg = null;
  20. Message msg = mMessages;
  21. //如果当前消息是异步消息,都将赋值给prevMsg,过滤掉,直到取到了非异步消息
  22. if (msg != null && msg.target == null) {
  23. do {
  24. prevMsg = msg;
  25. msg = msg.next;
  26. } while (msg != null && !msg.isAsynchronous());
  27. }
  28. //获取到了非异步消息
  29. if (msg != null) {
  30. //任务执行时间大于现在的时间
  31. if (now < msg.when) {
  32. //设置下一次轮询的超时时长
  33. nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
  34. } else {
  35. mBlocked = false;//指定为非阻塞任务
  36. if (prevMsg != null) {
  37. prevMsg.next = msg.next;
  38. } else {
  39. mMessages = msg.next;
  40. }
  41. msg.next = null;
  42. //设置消息的使用状态,即flags |= FLAG_IN_USE
  43. msg.markInUse();
  44. return msg; //成功地获取MessageQueue中的下一条即将要执行的消息
  45. }
  46. } else {
  47. //表示消息队列中无消息,会一直等待下去
  48. nextPollTimeoutMillis = -1;
  49. }
  50. ......
  51. //IdleHandler为发现线程何时阻塞的回调接口
  52. for (int i = 0; i < pendingIdleHandlerCount; i++) {
  53. final IdleHandler idler = mPendingIdleHandlers[i];
  54. mPendingIdleHandlers[i] = null; //去除handler引用
  55. boolean keep = false;
  56. //queueIdle返回true会被空闲的处理器处理,false就会被移走
  57. try {
  58. keep = idler.queueIdle(); //idle时执行的方法
  59. } catch (Throwable t) {
  60. Log.wtf(TAG, "IdleHandler threw exception", t);
  61. }
  62. if (!keep) {
  63. synchronized (this) {
  64. mIdleHandlers.remove(idler); //被移走
  65. }
  66. }
  67. }
  68. //重置idle handler个数为0,保证不会再次重复运行
  69. pendingIdleHandlerCount = 0;
  70. nextPollTimeoutMillis = 0;
  71. }
  72. }
  73. ————————————————
  74. 版权声明:本文为CSDN博主「魔法少女 厄加特」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
  75. 原文链接:https://blog.csdn.net/qq_37321098/article/details/81535449

移除消息

  1. void removeMessages(Handler h, int what, Object object) {
  2. if (h == null) {
  3. return;
  4. }
  5. synchronized (this) {
  6. Message p = mMessages;
  7. //从消息队列的头部开始,移除所有符合条件的消息
  8. while (p != null && p.target == h && p.what == what
  9. && (object == null || p.obj == object)) {
  10. Message n = p.next;
  11. mMessages = n;
  12. p.recycleUnchecked();
  13. p = n;
  14. }
  15. //移除剩余的符合要求的消息
  16. while (p != null) {
  17. Message n = p.next;
  18. if (n != null) {
  19. if (n.target == h && n.what == what
  20. && (object == null || n.obj == object)) {
  21. Message nn = n.next;
  22. n.recycleUnchecked();
  23. p.next = nn;
  24. continue;
  25. }
  26. }
  27. p = n;
  28. }
  29. }
  30. }
  31. void removeCallbacksAndMessages(Handler h, Object object) {
  32. if (h == null) {
  33. return;
  34. }
  35. synchronized (this) {
  36. Message p = mMessages;
  37. while (p != null && p.target == h
  38. && (object == null || p.obj == object)) {
  39. Message n = p.next;
  40. mMessages = n;
  41. p.recycleUnchecked();
  42. p = n;
  43. }
  44. while (p != null) {
  45. Message n = p.next;
  46. if (n != null) {
  47. if (n.target == h && (object == null || n.obj == object)) {
  48. Message nn = n.next;
  49. n.recycleUnchecked();
  50. p.next = nn;
  51. continue;
  52. }
  53. }
  54. p = n;
  55. }
  56. }
  57. }

参考链接

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

作用: Handler接收和处理的消息对象

创建 Message

  1. // 创建 Message
  2. val message = Message.obtain()
  3. val message = handler.obtainMessage()

Message 解析

  1. /**
  2. * 用于分类 Message 的类型
  3. */
  4. public int what;
  5. /**
  6. * 如果您只需要存储几个整数值,那么arg1和arg2是使用
  7. * {@link #setData(Bundle) setData()}的较低成本的替代方法
  8. */
  9. public int arg1;
  10. /**
  11. * 如果您只需要存储几个整数值,那么arg1和arg2是使用
  12. * {@link #setData(Bundle) setData()}的较低成本的替代方法
  13. */
  14. public int arg2;
  15. /**
  16. * 要发送给收件人的任意对象
  17. */
  18. public Object obj;
  19. /**
  20. * 传递 Messenger, 用于通过 Messenger 回复消息
  21. */
  22. public Messenger replyTo;