Handler同步屏障

 

 handler中的消息队列就类似于我们平时排队买电影票一个原理,都是按照顺序一个一个处理每一个人都是一个消息。大家都是排队买票,按照顺序,这种用户称为普通消息,如果这时候店老板来了,说持有vip的优先处理,那么vip用户就可以插队优先处理了,那么老板就是一个同步屏障消息,持有vip的人就是异步消息

在messageQueue中,遇到了同步屏障消息,那么消息队列会遍历后续的消息,标记其中的异步消息,优先处理异步消息,忽略同步消息,直到同步屏障的消息被移除后,才开始处理同步消息。这就是同步屏障机制。

通常,我们发送的message中的target都是有值的,即负责处理的handler,当把target为null 的时候,这条消息就被称为同步屏障消息。

 

来个demo练习一下,可以复制代码,自己试一下~

ui样式 

 

布局文件就4个按钮

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".handler.HandlerActivity">


    <Button
        android:onClick="sendSyncBarrier"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="100dp"
        android:text="发送同步屏障消息" />


    <Button
        android:onClick="sendSyncMsg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送同步消息" />


    <Button
        android:onClick="sendAsyncMsg"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送异步消息" />


    <Button
        android:onClick="removeSyncBarrier"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="移除同步屏障" />
</LinearLayout>

java代码:

package com.example.myanimationproject.handler

import android.annotation.SuppressLint
import android.os.*
import android.util.Log
import android.view.View
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import com.example.myanimationproject.R
import java.lang.reflect.Method


class HandlerActivity : AppCompatActivity() {


    lateinit var handler: Handler

    val MESSAGE_TYPE_SYNC = 1
    val MESSAGE_TYPE_ASYN = 2

    private var token: Int = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_handler)


        initHandler()
    }

    private fun initHandler() {
        Thread {
            Looper.prepare()

            handler = Handler(Handler.Callback {

                Log.d("chenhua", "接收到了消息--------------------")
                if (it.what == MESSAGE_TYPE_SYNC) {
                    Log.d("chenhua", "收到   普通   消息")
                } else if (it.what == MESSAGE_TYPE_ASYN) {
                    Log.d("chenhua", "收到了   异步   消息")
                }
                false
            })

            Looper.loop()
        }.start()
    }


    /**
     * 发送同步屏障
     */
    @SuppressLint("DiscouragedPrivateApi")
    @RequiresApi(Build.VERSION_CODES.M)
    fun sendSyncBarrier(view: View) {

        Log.d("chenhua", "插入同步屏障")
        val queue = handler.looper.queue

        //通过反射调用发送同步屏障的方法
        val method = MessageQueue::class.java.getDeclaredMethod("postSyncBarrier")
        method.isAccessible = true
        token = method.invoke(queue) as Int
    }


    /**
     * 发送同步消息
     */
    fun sendSyncMsg(view: View) {
        Log.d("chenhua", "插入普通消息")
        val message = Message.obtain()
        message.what = MESSAGE_TYPE_SYNC
        handler.sendMessageDelayed(message, 1000)
    }

    /**
     * 发送异步消息
     */
    @RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)
    fun sendAsyncMsg(view: View) {
        Log.d("chenhua", "插入异步消息")
        val message = Message.obtain()
        message.what = MESSAGE_TYPE_ASYN
        // 设置消息为异步消息
        message.isAsynchronous = true
        handler.sendMessageDelayed(message, 1000)
    }


    /**
     * 移除同步屏障
     */
    @SuppressLint("DiscouragedPrivateApi")
    @RequiresApi(Build.VERSION_CODES.M)
    fun removeSyncBarrier(view: View) {

        Log.d("chenhua", "移除屏障")

        val queue: MessageQueue = handler.looper.queue
        val method: Method = MessageQueue::class.java.getDeclaredMethod("removeSyncBarrier",
                Int::class.javaPrimitiveType)
        method.isAccessible = true
        method.invoke(queue, token)

    }


}

 运行·结果:

 

2021-06-03 11:30:25.899 9596-9596/com.example.myanimationproject D/chenhua: 插入普通消息
2021-06-03 11:30:26.172 9596-9596/com.example.myanimationproject D/chenhua: 插入异步消息
2021-06-03 11:30:26.442 9596-9596/com.example.myanimationproject D/chenhua: 插入普通消息
2021-06-03 11:30:26.656 9596-9596/com.example.myanimationproject D/chenhua: 插入异步消息
2021-06-03 11:30:26.901 9596-9621/com.example.myanimationproject D/chenhua: 接收到了消息--------------------
2021-06-03 11:30:26.901 9596-9621/com.example.myanimationproject D/chenhua: 收到   普通   消息
2021-06-03 11:30:27.173 9596-9621/com.example.myanimationproject D/chenhua: 接收到了消息--------------------
2021-06-03 11:30:27.173 9596-9621/com.example.myanimationproject D/chenhua: 收到了   异步   消息
2021-06-03 11:30:27.443 9596-9621/com.example.myanimationproject D/chenhua: 接收到了消息--------------------
2021-06-03 11:30:27.443 9596-9621/com.example.myanimationproject D/chenhua: 收到   普通   消息
2021-06-03 11:30:27.658 9596-9621/com.example.myanimationproject D/chenhua: 接收到了消息--------------------
2021-06-03 11:30:27.658 9596-9621/com.example.myanimationproject D/chenhua: 收到了   异步   消息

通常情况下,发送的普通消息和异步消息都是按照顺序执行的

现在插入一个同步屏障消息,然后再插入几个同步消息

2021-06-03 11:30:37.905 9596-9596/com.example.myanimationproject D/chenhua: 插入同步屏障
2021-06-03 11:30:39.886 9596-9596/com.example.myanimationproject D/chenhua: 插入普通消息
2021-06-03 11:30:40.135 9596-9596/com.example.myanimationproject D/chenhua: 插入普通消息

等待几秒之后,发现依然没有收到同步消息,可以证明,同步消息确实被屏蔽了

现在再插入异步消息试试看

2021-06-03 11:31:25.346 9596-9596/com.example.myanimationproject D/chenhua: 插入异步消息
2021-06-03 11:31:25.602 9596-9596/com.example.myanimationproject D/chenhua: 插入异步消息
2021-06-03 11:31:26.348 9596-9621/com.example.myanimationproject D/chenhua: 接收到了消息--------------------
2021-06-03 11:31:26.348 9596-9621/com.example.myanimationproject D/chenhua: 收到了   异步   消息
2021-06-03 11:31:26.603 9596-9621/com.example.myanimationproject D/chenhua: 接收到了消息--------------------
2021-06-03 11:31:26.604 9596-9621/com.example.myanimationproject D/chenhua: 收到了   异步   消息

发现异步消息是可以正常接收的,并且在前面插入的2条同步消息已经被忽略了,并未执行,而是直接执行的异步消息


现在移除同步屏障消息

2021-06-03 11:33:51.915 9596-9596/com.example.myanimationproject D/chenhua: 移除屏障
2021-06-03 11:33:51.916 9596-9621/com.example.myanimationproject D/chenhua: 接收到了消息--------------------
2021-06-03 11:33:51.916 9596-9621/com.example.myanimationproject D/chenhua: 收到   普通   消息
2021-06-03 11:33:51.916 9596-9621/com.example.myanimationproject D/chenhua: 接收到了消息--------------------
2021-06-03 11:33:51.916 9596-9621/com.example.myanimationproject D/chenhua: 收到   普通   消息

发现很快就收到了之前发送的普通消息

再次啰嗦一句:同步屏障消息可以屏蔽当前消息队列中的同步消息,遍历消息队列中的异步消息,优先执行异步消息,并忽略同步消息。直到移除同步屏障消息,才恢复正常,按照顺序执行,否则同步消息将无法正常执行

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值