您当前的位置: 首页 > 
  • 0浏览

    0关注

    674博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

handler的同步屏障使用场景

沙漠一只雕得儿得儿 发布时间:2021-04-01 14:49:49 ,浏览量:0

Message分类:
  • 同步消息:正常情况下通过Handler发送的Message都属于同步消息,除非在发送的时候指定其是一个异步消息,同步消息会按顺序排列在队列中。
  • 异步消息:一般情况下与同步消息没有区别,只有在设置了同步屏障(barrier)时才有所不同。
  • 屏障消息(Barrier):屏障(Barrier)是一种特殊的Message,它的target为null(只有屏障的target可以为null),并且arg1属性被用作屏障的标识符来区别不同的屏障。屏障的作用是用于拦截队列中同步消息,放行异步消息。

同步异步消息类型由 isAsynchronous 方法得到,通过 MessageQueue.postSyncBarrier() 方法可以发送一个Barrier。当发现遇到barrier后,队列中后续的同步消息会被阻塞,而异步消息则不受barrier的影响,直到通过调用MessageQueue.removeSyncBarrier()释放了指定的barrier。屏障和普通消息一样可以根据时间来插入到消息队列中的适当位置,并且只会挡住它后面的同步消息的分发。插入普通消息会唤醒消息队列,但是插入屏障不会。

https://ljd1996.github.io/2020/01/06/Android%E6%B6%88%E6%81%AF%E6%9C%BA%E5%88%B6/#postSyncBarrier

  使用场景:

为当前线程的 MessageQueue 添加同步屏障来屏蔽同步消息,保证 VSync 信号到来后立即执行绘制,而不是要等前面的同步消息。

https://juejin.cn/post/6894206842277199880

系统显示原理:

显示系统一般包括 CPU, GPU 以及 Display 三个部分,CPU负责计算帧数据,把计算好的数据交给GPU,GPU会对图形数据进行渲染,渲染好后放到buffer(图像缓冲区)里存起来,然后Display(屏幕或显示器)负责把buffer里的数据呈现到屏幕上。当然实际上的流程要复杂许多,比如说 APP 绘制过程中会涉及到软件绘制和硬件加速,以及通过 Surface 向图形缓存区写入渲染数据,另外在 SurfaceFlinger 进程会将这些不同 Surface(Layer) 的数据合成交给显示器的缓存区等等。

最近在整理 Android 图形系统相关的流程,为了对这些知识点有一个系统的理解,一边阅读别人的博客总结,一边阅读系统源码,之前总结过 SurfaceFlinger 启动与工作流程,这篇文章再看一下 Choreographer 与 Vsync 信号之间的相关工作,后续会更新一下 Surface 及 Layer 在 View 绘制过程中的数据走向,最后将这些内容结合起来,把整个图形系统的工作逻辑串联起来,然后再分开看这些知识点,应该就会有一个比较好的效果。源码解析过程中难免有所错误,如果发现了欢迎指正哈!

Choreographer: 编舞者,用来控制当收到 VSync 信号后才开始绘制任务,保证绘制拥有完整的16.6ms。

入口: scheduleTraversals

从 Android-Window机制原理 可知,在调用 context.startActivity 后,经过 AMS 的一些处理,后面又通过 Binder 调用目标进程的 ActivityThread.handleResumeActivity 方法,在这个方法里会回调目标 Activity 的 onResume 和 makeVisible 方法,在 makeVisible 方法里完成 WindowManager.addView 的过程,这个过程调用了 ViewRootImpl.setView方 法,内部又调用其 scheduleTraversals 方法,最后会走到 performTraversals 方法,接着就到了熟悉的 measure,layout,draw 三大流程了。

另外,查看 View.invalidate 方法的源码,也可以发现最后会调用到 ViewRootImpl.scheduleTraversals 方法。

// ViewRootImpl
final ViewRootHandler mHandler = new ViewRootHandler();

void scheduleTraversals() {
    if (!mTraversalScheduled) {
        // 保证同时间多次更改只会刷新一次,例如TextView连续两次setText()也只会走一次绘制流程
        mTraversalScheduled = true;
        // 添加同步屏障,保证 VSync 到来立即执行绘制
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        // ...
    }
}

// mTraversalRunnable 是一个 Runnable 实例
final class TraversalRunnable implements Runnable {
    @Override
    public void run() {
        doTraversal();
    }
}

void doTraversal() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        // 移除同步屏障
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        // 真正执行View的measure,layout,draw流程
        performTraversals();
    }
}
复制代码

首先使用 mTraversalScheduled 字段保证同时间多次更改只会刷新一次,然后为当前线程的 MessageQueue 添加同步屏障来屏蔽同步消息,保证 VSync 信号到来后立即执行绘制,而不是要等前面的同步消息。调用 mChoreographer.postCallback() 方法发送了一个会在下一帧执行的回调,即在下一个 VSync 信号到来时会执行TraversalRunnable-->doTraversal()-->performTraversals()-->绘制流程。同步屏障可以参考 Android消息机制(https://ljd1996.github.io/2020/01/06/Android%E6%B6%88%E6%81%AF%E6%9C%BA%E5%88%B6/#postSyncBarrier)。

 

关注
打赏
1657159701
查看更多评论
立即登录/注册

微信扫码登录

0.0377s