一、消息种类

关于Handler机制的基本原理不了解可以看这里: Handler机制源码解析。

Message分为3种:普通消息(同步消息)、屏障消息(同步屏障)和异步消息。我们通常使用的都是普通消息,而屏障消息就是在消息队列中插入一个屏障,在屏障之后的所有普通消息都会被挡着,不能被处理。不过异步消息却例外,屏障不会挡住异步消息,因此可以这样认为:屏障消息就是为了确保异步消息的优先级,设置了屏障后,只能处理其后的异步消息,同步消息会被挡住,除非撤销屏障。

二、什么是屏障消息

同步屏障是通过MessageQueue的postSyncBarrier方法插入到消息队列的。

MessageQueue#postSyncBarrierprivate int postSyncBarrier(long when) {synchronized (this) {final int token = mNextBarrierToken++;//1、屏障消息和普通消息的区别是屏障消息没有tartget。final Message msg = Message.obtain();msg.markInUse();msg.when = when;msg.arg1 = token;Message prev = null;Message p = mMessages;//2、根据时间顺序将屏障插入到消息链表中适当的位置if (when != 0) {while (p != null && p.when <= when) {prev = p;p = p.next;}}if (prev != null) { // invariant: p == prev.nextmsg.next = p;prev.next = msg;} else {msg.next = p;mMessages = msg;}//3、返回一个序号,通过这个序号可以撤销屏障return token;}}

postSyncBarrier方法就是用来插入一个屏障到消息队列的,可以看到它很简单,从这个方法我们可以知道如下:

  • 屏障消息和普通消息的区别在于屏障没有tartget,普通消息有target是因为它需要将消息分发给对应的target,而屏障不需要被分发,它就是用来挡住普通消息来保证异步消息优先处理的。
  • 屏障和普通消息一样可以根据时间来插入到消息队列中的适当位置,并且只会挡住它后面的同步消息的分发。
  • postSyncBarrier返回一个int类型的数值,通过这个数值可以撤销屏障。
  • 插入普通消息会唤醒消息队列,但是插入屏障不会。

三、屏障消息的工作原理

通过postSyncBarrier方法屏障就被插入到消息队列中了,那么屏障是如何挡住普通消息只允许异步消息通过的呢?我们知道MessageQueue是通过next方法来获取消息的。

Message next() {//1、如果有消息被插入到消息队列或者超时时间到,就被唤醒,否则阻塞在这。nativePollOnce(ptr, nextPollTimeoutMillis);synchronized (this) {        Message prevMsg = null;Message msg = mMessages;if (msg != null && msg.target == null) {//2、遇到屏障  msg.target == nulldo {prevMsg = msg;msg = msg.next;} while (msg != null && !msg.isAsynchronous());//3、遍历消息链表找到最近的一条异步消息}if (msg != null) {//4、如果找到异步消息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;if (DEBUG) Log.v(TAG, "Returning message: " + msg);msg.markInUse();return msg;}} else {// 如果没有异步消息就一直休眠,等待被唤醒。nextPollTimeoutMillis = -1;}//。。。。}}

可以看到,在注释2如果碰到屏障就遍历整个消息链表找到最近的一条异步消息,在遍历的过程中只有异步消息才会被处理执行到 if (msg != null){}中的代码。可以看到通过这种方式就挡住了所有的普通消息。

四、如何发送异步消息

Handler有几个构造方法,可以传入async标志为true,这样构造的Handler发送的消息就是异步消息。不过可以看到,这些构造函数都是hide的。

     /*** @hide*/public Handler(boolean async) {}/*** @hide*/public Handler(Callback callback, boolean async) { }/*** @hide*/public Handler(Looper looper, Callback callback, boolean async) {}

当调用handler.sendMessage(msg)发送消息,最终会走到:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {msg.target = this;if (mAsynchronous) {msg.setAsynchronous(true);//把消息设置为异步消息}return queue.enqueueMessage(msg, uptimeMillis);}

可以看到如果这个handler的mAsynchronous为true就把消息设置为异步消息,设置异步消息其实也就是设置msg内部的一个标志。而这个mAsynchronous就是构造handler时传入的async。除此之外,还有一个公开的方法:

     Message message=Message.obtain();message.setAsynchronous(true);handler.sendMessage(message);

在发送消息时通过 message.setAsynchronous(true)将消息设为异步的,这个方法是公开的,我们可以正常使用。

五、移除屏障

移除屏障可以通过MessageQueue的removeSyncBarrier方法:

//注释已经写的很清楚了,就是通过插入同步屏障时返回的token 来移除屏障
/*** Removes a synchronization barrier.** @param token The synchronization barrier token that was returned by* {@link #postSyncBarrier}.** @throws IllegalStateException if the barrier was not found.** @hide*/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;//找到token对应的屏障while (p != null && (p.target != null || p.arg1 != token)) {prev = p;p = p.next;}final boolean needWake;//从消息链表中移除if (prev != null) {prev.next = p.next;needWake = false;} else {mMessages = p.next;needWake = mMessages == null || mMessages.target != null;}//回收这个Message到对象池中。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);//唤醒消息队列}}

六、实战

1、当点击同步消息会发送一个延时1秒执行普通消息,执行的结果打印log。

2、同步屏障会挡住同步消息。通过点击发送同步屏障->发送同步消息->移除同步消息测试

3、当点击发送同步屏障,会挡住同步消息,但是不会挡住异步消息。通过点击插入同步屏障->插入同步消息->插入异步消息->移除同步屏障 来测试(需要注意不要通过弹土司来测试,通过打印log。不然看不出效果)

测试代码如下(省略布局文件):

public class MainActivity extends AppCompatActivity implements View.OnClickListener {private Handler handler;private int token;public static final int MESSAGE_TYPE_SYNC=1;public static final int MESSAGE_TYPE_ASYN=2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initHandler();initListener();}private void initHandler() {new Thread(new Runnable() {@Overridepublic void run() {Looper.prepare();handler=new Handler(){@Overridepublic void handleMessage(Message msg) {if (msg.what == MESSAGE_TYPE_SYNC){Log.d("MainActivity","收到普通消息");}else if (msg.what == MESSAGE_TYPE_ASYN){Log.d("MainActivity","收到异步消息");}}};Looper.loop();}}).start();}private void initListener() {findViewById(R.id.btn_postSyncBarrier).setOnClickListener(this);findViewById(R.id.btn_removeSyncBarrier).setOnClickListener(this);findViewById(R.id.btn_postSyncMessage).setOnClickListener(this);findViewById(R.id.btn_postAsynMessage).setOnClickListener(this);}//往消息队列插入同步屏障@RequiresApi(api = Build.VERSION_CODES.M)public void sendSyncBarrier(){try {Log.d("MainActivity","插入同步屏障");MessageQueue queue=handler.getLooper().getQueue();Method method=MessageQueue.class.getDeclaredMethod("postSyncBarrier");method.setAccessible(true);token= (int) method.invoke(queue);} catch (Exception e) {e.printStackTrace();}}//移除屏障@RequiresApi(api = Build.VERSION_CODES.M)public void removeSyncBarrier(){try {Log.d("MainActivity","移除屏障");MessageQueue queue=handler.getLooper().getQueue();Method method=MessageQueue.class.getDeclaredMethod("removeSyncBarrier",int.class);method.setAccessible(true);method.invoke(queue,token);} catch (Exception e) {e.printStackTrace();}}//往消息队列插入普通消息public void sendSyncMessage(){Log.d("MainActivity","插入普通消息");Message message= Message.obtain();message.what=MESSAGE_TYPE_SYNC;handler.sendMessageDelayed(message,1000);}//往消息队列插入异步消息@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP_MR1)private void sendAsynMessage() {Log.d("MainActivity","插入异步消息");Message message=Message.obtain();message.what=MESSAGE_TYPE_ASYN;message.setAsynchronous(true);handler.sendMessageDelayed(message,1000);}@RequiresApi(api = Build.VERSION_CODES.M)@Overridepublic void onClick(View v) {int id=v.getId();if (id == R.id.btn_postSyncBarrier) {sendSyncBarrier();}else if (id == R.id.btn_removeSyncBarrier) {removeSyncBarrier();}else if (id == R.id.btn_postSyncMessage) {sendSyncMessage();}else if (id == R.id.btn_postAsynMessage){sendAsynMessage();}}}

Handler机制——同步屏障相关推荐

  1. android同步方法和对象的区别是什么,(4.1.10.8)Android Handler之同步屏障机制(sync barrier)...

    一.概述 简单理解为 异步消息插队并优先执行. 场景:排队买票 先来了一个普通用户来排队,买完票走了. 后面又来了一个VIP用户A来买票 就一直站在卖窗口这里 也不走(ps:添加屏障 ) 紧接者又来了 ...

  2. 什么是Handler的同步屏障机制?

    前言 对于Handler机制,想必大家都已经非常熟悉了吧,从迈进Android开发这扇大门的时候,就不停的研究和使用它,同样的这也是Android系统架构的精髓之一.然而在我们使用的时候,往往会忽略掉 ...

  3. Android:同步屏障的简单理解和使用

    同步屏障的简单理解和使用 1.背景 2.何为同步屏障? 2.1. 发送屏障消息--postSyncBarrier 2.2.发送异步消息 2.3.处理消息 2.4.移除屏障消息--removeSyncB ...

  4. Handler sync barrier(同步屏障)

    Handler中的Message可以分为两类:同步消息.异步消息.消息类型可以通过以下函数得知 //Message.java public boolean isAsynchronous() {retu ...

  5. handler机制的原理_5分钟了解Handler错误使用场景

    码个蛋(codeegg)第 821 次推文 作者:刁儿郎当 博客:https://www.jianshu.com/p/43e21be8d849 码妞看世界 小燕子叶 写在前面 Handler的相关博客 ...

  6. android handle 阻塞,Android全面解析之Handler机制:常见问题汇总

    主线程为什么不用初始化Looper? 答:因为应用在启动的过程中就已经初始化主线程Looper了. 每个java应用程序都是有一个main方法入口,Android是基于Java的程序也不例外.Andr ...

  7. handler机制的原理_Handler机制竟然可以这样解释,我惊呆了!

    Handler的相关博客太多了,随便一搜都一大把,但是基本都是上来就贴源码,讲姿势,短时间不太好弄明白整体的关系,和流程,本文就以生活点餐的例子再结合源码原理进行解析.希望对你有一点帮助. 来,咱们进 ...

  8. Android消息机制(Handler机制) - 线程的等待和唤醒

    我们都知道,Android的Handler机制,会在线程中开启消息循环,不断的从消息队列中取出消息,这个机制保证了主线程能够及时的接收和处理消息. 通常在消息队列中(MessageQueue)中没有消 ...

  9. Handler消息Message屏障消息

    Message分为3中:普通消息(同步消息).屏障消息(同步屏障)和异步消息.我们通常使用的都是普通消息,而屏障消息就是在消息队列中插入一个屏障(也是一个消息,这个消息会保存到当前Hanlder中,直 ...

最新文章

  1. 网络推广专员浅析站内网络推广引流怎样做?
  2. 使用nginx做反向代理和负载均衡效果图
  3. Java的值传递解析
  4. 【论文笔记】LINE:大规模信息网络嵌入
  5. xml文件的创建和插入节点【原创】
  6. .sln vcxproj vcxproj.filter文件作用(转载)
  7. android 编译 bison,Ubuntu搭建android编译环境问题总结
  8. 安装 tensorflow 环境
  9. 【专栏必读】数据库系统概论第五版(王珊)专栏学习笔记目录导航及课后习题答案详解
  10. 常用的sql语句整理 增删改查
  11. 基于wincc的虚拟电梯设计_PLC基于WinCC的四层电梯监控系统设计+梯形图
  12. 【算法】合并两个有序链表
  13. css 实现一个尖角_css3如何做尖角标签效果?
  14. 还原故事的真相:少年派毫不奇幻的残酷漂流
  15. CLEAR: Contrastive Learning for Sentence Representation
  16. 图像情感分析标签分布学习
  17. 寒武纪“失速”,是AI芯片行业的阵痛?
  18. Kaggle数据集之电信客户流失数据分析
  19. 元气骑士(联机版)java合作大作业
  20. 关于数据中台、数据平台、数据仓库、数据湖等数据概念的对比解析

热门文章

  1. Gause算法c语言实现,Gause是什么意思
  2. 手机联网总是显示正在连接服务器,手机老显示网络连接超时是什么意思
  3. Python爬虫自学要多久?
  4. NISI脚本中对环境变量赋值
  5. C++求两个集合的交集
  6. “砍一刀”潜力巨大? 拼多多海外版成美国下载量最高应用
  7. 21考研,什么时候开始准备,越早越好吗?
  8. Java中数字格式化
  9. java j2me_j2mejava最强版下载
  10. 如何解决无法停止‘通用卷’设备的故障