当前位置: 首页 > news >正文

Android Handler之消息同步屏障

文章目录

  • Android Handler之消息同步屏障
    • 概述
    • 源码分析
      • 开启消息屏障
      • 取异步消息
      • 删除消息屏障
    • 应用场景

Android Handler之消息同步屏障

概述

同步屏障:即消息的同步阻碍,指阻碍同步消息,只让异步消息通过。

平时我们通过 Handler 发送到消息大部分都是同步消息,当然也可以设置为异步消息。

源码分析

开启消息屏障

通过 MessageQueue#postSyncBarrier() 开启消息屏障。

// MessageQueue.javapublic int postSyncBarrier() {return postSyncBarrier(SystemClock.uptimeMillis());
}private int postSyncBarrier(long when) {    synchronized (this) {final int token = mNextBarrierToken++;// 从消息池中获取Messagefinal Message msg = Message.obtain();msg.markInUse();// 没有给target赋值,没有绑定Handlermsg.when = when;msg.arg1 = token;Message prev = null;Message p = mMessages;if (when != 0) {while (p != null && p.when <= when) {// 如果开启同步屏障的时间(假设记为T)T不为0,且当前的同步消息里有时间小于T,则prev也不为nullprev = p;p = p.next;}}// 将msg插入到消息队列中if (prev != null) {  msg.next = p;prev.next = msg;} else {msg.next = p;mMessages = msg;}return token;}
}

取异步消息

Message next() {int nextPollTimeoutMillis = 0;// 死循环for (;;) {if (nextPollTimeoutMillis != 0) {Binder.flushPendingCommands();}nativePollOnce(ptr, nextPollTimeoutMillis);synchronized (this) {final long now = SystemClock.uptimeMillis();Message prevMsg = null;Message msg = mMessages;// 如果msg.target为null,表示收到消息同步屏障,循环遍历查找第一个异步消息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 {// Got a message.mBlocked = false;if (prevMsg != null) {prevMsg.next = msg.next;} else {mMessages = msg.next;}msg.next = null;if (DEBUG) Log.v(TAG, "Returning message: " + msg);msg.markInUse();return msg;}} else {nextPollTimeoutMillis = -1;}// ...}}
}

删除消息屏障

通过 MessageQueue#removeSyncBarrier() 删除消息屏障,并唤醒。

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

应用场景

日常的应用开发中,很少会用到同步屏障。主要是 Android 系统中的 UI 更新相关的消息即为异步消息,需要优先处理。如,在 View 更新时,draw、requestLayout、invalidate 等很多地方都调用了。

// ViewRootImpl.javavoid scheduleTraversals() {if (!mTraversalScheduled) {mTraversalScheduled = true;// 开启同步屏障mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();// 最终调用Choreographer#postCallbackDelayedInternal()mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);notifyRendererOfFramePending();pokeDrawLockIfNeeded();}
}
// Choreographer.javaprivate void postCallbackDelayedInternal(int callbackType,Object action, Object token, long delayMillis) {if (DEBUG_FRAMES) {Log.d(TAG, "PostCallback: type=" + callbackType+ ", action=" + action + ", token=" + token+ ", delayMillis=" + delayMillis);}synchronized (mLock) {final long now = SystemClock.uptimeMillis();final long dueTime = now + delayMillis;mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);if (dueTime <= now) {scheduleFrameLocked(now);} else {// 发送异步消息Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);msg.arg1 = callbackType;msg.setAsynchronous(true);mHandler.sendMessageAtTime(msg, dueTime);}}
}
// ViewRootImpl.javavoid unscheduleTraversals() {if (mTraversalScheduled) {mTraversalScheduled = false;// 移除消息同步屏障mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);mChoreographer.removeCallbacks(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Linux下如何安装配置Fail2ban防护工具
  • Postman中的数据驱动测试:API测试数据准备全攻略
  • HTML + CSS编程规范
  • MLIR的TOY教程学习笔记
  • wget下载github文件得到html文件
  • 2024年自动驾驶规划控制面试及答案
  • AI测试入门:认识AI大语言模型(LLM)
  • Excel下载模板文件和导入文件的步骤
  • Windows:批处理脚本学习
  • 【BUG】已解决:IndexError: positional indexers are out-of-bounds
  • C++树形结构(1 基础)
  • CSP-J模拟赛day1——试题
  • 锁相环 vivado FPGA
  • centos中zabbix安装、卸载及遇到的问题
  • Pytest进阶之fixture的使用(超详细)
  • 【Leetcode】101. 对称二叉树
  • 【comparator, comparable】小总结
  • 230. Kth Smallest Element in a BST
  • 4. 路由到控制器 - Laravel从零开始教程
  • AHK 中 = 和 == 等比较运算符的用法
  • angular组件开发
  • C++入门教程(10):for 语句
  • const let
  •  D - 粉碎叛乱F - 其他起义
  • Eureka 2.0 开源流产,真的对你影响很大吗?
  • isset在php5.6-和php7.0+的一些差异
  • JavaSE小实践1:Java爬取斗图网站的所有表情包
  • java第三方包学习之lombok
  • Java-详解HashMap
  • mysql 数据库四种事务隔离级别
  • python docx文档转html页面
  • Vue学习第二天
  • 给Prometheus造假数据的方法
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 关于extract.autodesk.io的一些说明
  • 深入体验bash on windows,在windows上搭建原生的linux开发环境,酷!
  • 学习笔记DL002:AI、机器学习、表示学习、深度学习,第一次大衰退
  • 最简单的无缝轮播
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • ​flutter 代码混淆
  • #、%和$符号在OGNL表达式中经常出现
  • #07【面试问题整理】嵌入式软件工程师
  • #C++ 智能指针 std::unique_ptr 、std::shared_ptr 和 std::weak_ptr
  • (javaweb)Http协议
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (二)丶RabbitMQ的六大核心
  • (附源码)spring boot智能服药提醒app 毕业设计 102151
  • (附源码)计算机毕业设计高校学生选课系统
  • (十一)c52学习之旅-动态数码管
  • (转)h264中avc和flv数据的解析
  • (转贴)用VML开发工作流设计器 UCML.NET工作流管理系统
  • (自用)交互协议设计——protobuf序列化
  • .gitattributes 文件
  • .md即markdown文件的基本常用编写语法
  • .NET 4.0中的泛型协变和反变