Android帧绘制流程深度解析 (一)

news2024/11/24 18:46:20

Android帧绘制技术有很多基础的知识,比如多buffer、vsync信号作用等基础知识点很多笔记讲的已经很详细了,我也不必再去总结,所以此处不再过多赘述安卓帧绘制技术,基础知识这篇文章总结的很好,一文读懂"系列:Android屏幕刷新机制 - 掘金 (juejin.cn),本文重点记录代码的学习笔记。
代码流程图:在这里插入图片描述

1、 Invalidate()

Android帧绘制的入口就是invalidate()函数,在调用invalidate函数后,当前界面上的内容就会被设置为脏区,需要进行更新。

void invalidate() {
    mDirty.set(0, 0, mWidth, mHeight);
    if (!mWillDrawSoon) {//防止在更新界面时,重复触发更新流程
        scheduleTraversals();
    }
}

2、 scheduleTraversals

void scheduleTraversals() {
    if (!mTraversalScheduled) {//同样是防止重复触发界面更新流行
        mTraversalScheduled = true;
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();//开启同步屏障,让帧绘//制的消息尽快得到处理
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);//(1)发送帧绘制的消息,以请求vsync信号。
        notifyRendererOfFramePending();
        pokeDrawLockIfNeeded();
    }
}

(1)处通过choreographer触发请求vsync流程。
此处的调用逻辑如流程图中5-7,最后调用到了postCallbackDelayedInternal方法:

private 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;//上面调用过来的时候,时间延迟为0
        mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);//将callback放进callbackQueue中,不同的callbackType对应不用的事件,后面再具体说明,此处type是Traversal

        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);//时间还没到,所以通过延迟消息触发请求vsync流程
        }
    }
}

3、 scheduleFrameLocked:

因为帧绘制都是立即执行的,所以此处直接查看scheduleFrameLocked,其实如果是走到延迟消息的话,流程也差不多,这里大概的解释下:
首先通过mHandler.sendMessageAtTime(msg, dueTime)发送延时消息,消息的target就是choreographer中的mHandler,而mHandler的类型是FrameHandler。所以找到FrameHandler的定义:

private final class FrameHandler extends Handler {
    public FrameHandler(Looper looper) {
        super(looper);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case MSG_DO_FRAME:
                doFrame(System.nanoTime(), 0, new DisplayEventReceiver.VsyncEventData());
                break;
            case MSG_DO_SCHEDULE_VSYNC:
                doScheduleVsync();
                break;
            case MSG_DO_SCHEDULE_CALLBACK:
                doScheduleCallback(msg.arg1);//此处会走到这里。
                break;
        }
    }
}

可以看到此处会走到case2,然后继续往下找就是这里:

void doScheduleCallback(int callbackType) {
    synchronized (mLock) {
        if (!mFrameScheduled) {
            final long now = SystemClock.uptimeMillis();
            if (mCallbackQueues[callbackType].hasDueCallbacksLocked(now)) {
                scheduleFrameLocked(now);
            }
        }
    }
}

所以最终还是走到了scheduleFrameLocked方法了。再次回到scheduleFrameLocked方法的解读:

private void scheduleFrameLocked(long now) {
    if (!mFrameScheduled) {//同样是为了防止重复触发该流程。
        mFrameScheduled = true;
        if (USE_VSYNC) {//如果是使用Vsync机制,这里好像是android4之后都是默认使用vsync机制的
            if (DEBUG_FRAMES) {
                Log.d(TAG, "Scheduling next frame on vsync.");
            }
            if (isRunningOnLooperThreadLocked()) {//如果当前线程有looper的话
                scheduleVsyncLocked();//请求vsync
            } else {//如果当前线程无Looper的话需要通过消息机制发送消息到Looper线程进行触发
                Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_VSYNC);
                msg.setAsynchronous(true);
                mHandler.sendMessageAtFrontOfQueue(msg);
            }
        } else {//这里就是无vsync机制时的绘帧逻辑
            final long nextFrameTime = Math.max(
                    mLastFrameTimeNanos / TimeUtils.NANOS_PER_MS + sFrameDelay, now);
            if (DEBUG_FRAMES) {
                Log.d(TAG, "Scheduling next frame in " + (nextFrameTime - now) + " ms.");
            }
            Message msg = mHandler.obtainMessage(MSG_DO_FRAME);
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, nextFrameTime);
        }
    }
}

上述代码中有个比较有意思的概念,就是isRunningOnLooperThreadLocked()这个方法,这个方法的解读就是运行在looper线程上。方法定义如下:

private boolean isRunningOnLooperThreadLocked() {
    return Looper.myLooper() == mLooper;
}

这里可以参考之前的说Android消息机制这节内容,这个myLooper方法还会牵扯到ThreadLocal的内容,这里就不再细说,感兴趣的可以看看:Android消息机制-CSDN博客。
主要思想就是不是每个线程都会有Looper对象(choreographer的初始化参数中有Looper这个量),但是有Looper的都可以初始化一个choreographer,所以这里就是检查当前线程的Looper是否与choreographer关联的线程相同。

4、 scheduleVsyncLocked:

该方法用来请求Vsync信号:

private void scheduleVsyncLocked() {
    try {
        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#scheduleVsyncLocked");
        mDisplayEventReceiver.scheduleVsync();
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_VIEW);
    }
}

public void scheduleVsync() {
    if (mReceiverPtr == 0) {
        Log.w(TAG, "Attempted to schedule a vertical sync pulse but the display event "
                + "receiver has already been disposed.");
    } else {
        nativeScheduleVsync(mReceiverPtr);
    }
}

可以看到该方法能直接回调到native层的方法以请求Vsync。这里的native层的调用后续会再详细详细讲解,本次暂时还未学习,剩下的流程13-20还需要再仔细看看

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1813378.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

7.数据集处理库Hugging Face Datasets

数据集处理库Hugging Face Datasets Datasets 首先解决数据来源问题 使用 Datasets 下载开源数据集 Datasets.load_dataset 实现原理简介 构造 DatasetBuilder 类的主要配置 BuilderConfig 如果您想向数据集添加额外的属性,例如类别标签。有两种方法来填充BuilderConfig类或其…

web刷题记录(5)

[羊城杯 2020]easycon 进来以后就是一个默认测试页面&#xff0c; 在这种默认界面里&#xff0c;我觉得一般不会有什么注入点之类的&#xff0c;所以这里先选择用御剑扫扫目录看看有没有什么存在关键信息的页面 扫了一半发现&#xff0c;很多都是和index.php文件有关&#xff0…

【docker】adoptopenjdk/openjdk8-openj9:alpine-slim了解

adoptopenjdk/openjdk8-openj9:alpine-slim 是一个 Docker 镜像的标签&#xff0c;它指的是一个特定的软件包&#xff0c;用于在容器化环境中运行 Java 应用程序。 镜像相关的网站和资源&#xff1a; AdoptOpenJDK 官方网站 - AdoptOpenJDK 这是 AdoptOpenJDK 项目的官方网站&…

柯桥成人外语培训|职场商务英语剑桥国际英语口语外贸商务英语

01 “puppy love”是什么意思&#xff1f; 大家都知道&#xff0c;puppy有“幼犬&#xff0c;小狗”的意思&#xff0c;love是“爱”&#xff0c;那puppy love是什么意思呢&#xff1f;可不是字面上表达的小狗的爱哦&#xff01; 其实&#xff0c;"puppy love"真正的…

小巧精悍的电脑磁盘分析工具,程序大小仅830KB,支持汉化。

一、简介 1、一款小巧精悍的电脑磁盘分析工具&#xff0c;程序大小仅830KB&#xff0c;支持汉化&#xff1b;当你启动它&#xff0c;指定要分析的系统盘&#xff0c;它会自动将文件和文件夹按照所占用空间大小从小到大可视化显示。各个文件会以大小不同的块展示出来&#xff0c…

VirtFuzz:一款基于VirtIO的Linux内核模糊测试工具

关于VirtFuzz VirtFuzz是一款功能强大的Linux内核模糊测试工具&#xff0c;该工具使用LibAFL构建&#xff0c;可以利用VirtIO向目标设备的内核子系统提供输入测试用例&#xff0c;广大研究人员可以使用该工具测试Linux内核的安全性。 工具要求 1、Rust&#xff1b; 2、修补的Q…

word空白页删除不了怎么办?

上方菜单栏点击“视图”&#xff0c;下方点击“大纲视图”。找到文档分页符的位置。将光标放在要删除的分节符前&#xff0c;按下键盘上的“Delet”键删除分页符。

Linux基础(2)基础命令与vim

文件的复制和移动 cp 拷贝文件和目录 cp file file_copy --> file 是目标文件&#xff0c;file_copy 是拷贝出来的文件 cp file one --> 把 file 文件拷贝到 one 目录下&#xff0c;并且文件名依然为 file cp file one/file_copy --> 把 file 文件拷贝到 one 目录下…

vue input 限制输入,小数点后保留两位 以及 图片垂直居中显示 和 分享 git 小技巧

&#xff08;1&#xff09;input 限制输入&#xff0c;小数点后保留两位 <template><div><el-input v-model"number" input"checkNumber" blur"completeNumber" placeholder"请输入"></el-input></div>…

军事地图管理系统|DW-S403实现军用地图科学管理

军用地图管理系统DW-S403系统通过数据采集、物联网技术&#xff0c;实现数字化智能管控&#xff0c;以提高军用物资的地图的科学化管理&#xff0c;也有助于消除生产过程中的不确定性。 军用地图是反映实际地形的最可靠的资料&#xff0c;是指挥员的"左膀右臂"。在作…

[Algorithm][动态规划][二维费用的背包问题][一和零][盈利计划]详细讲解

目录 0.原理讲解1.一和零1.题目链接2.算法原理详解3.代码实现 2.盈利计划1.题目链接2.算法原理详解3.代码实现 0.原理讲解 本质仍然是背包问题&#xff0c;但是相较于普通的背包问题&#xff0c;只是限制条件多了一个而已 1.一和零 1.题目链接 一和零 2.算法原理详解 思路&…

03-3.5.1~4 特殊矩阵的压缩存储

&#x1f44b; Hi, I’m Beast Cheng&#x1f440; I’m interested in photography, hiking, landscape…&#x1f331; I’m currently learning python, javascript, kotlin…&#x1f4eb; How to reach me --> 458290771qq.com 喜欢《数据结构》部分笔记的小伙伴可以订…

vue elementui 自定义loading显示的icon 文本 背景颜色

<div v-loading"modalLoading"element-loading-text"拼命加载中"element-loading-spinner"el-icon-loading"element-loading-background"rgba(0, 0, 0, 0.8)" class"loading-box" v-if"modalLoading"></…

由于人工智能,他们的语言更容易理解

密歇根大学、墨西哥国家天体物理研究所和光学与电子研究所的研究人员正在使用人工智能模型来破译狗的语言。 在国际会议上提出的新研究展示了先进的人工智能 模型如何帮助人类了解动物。 密歇根大学人工智能实验室主任 Rada Mihalcea 强调了这项研究的重要性&#xff1a;对于…

初出茅庐的小李博客之CJSON库解析心知天气数据

心知天气数据JSON格式介绍 JSON格式介绍http://t.csdnimg.cn/pJX1n 下面代码是利用CJSON库进行数据解析 解析代码 #include <stdio.h> #include <string.h> #include "cJSON.h" // 假设你的CJSON库头文件路径是正确的int main(void) {// 提供的JSON…

微软如何打造数字零售力航母系列科普13 - Prime Focus Technologies在NAB 2024上推出CLEAR®对话人工智能联合试点

Prime Focus Technologies在NAB 2024上推出CLEAR对话人工智能联合试点 彻底改变您与内容的互动方式&#xff0c;从内容的创建到分发 洛杉矶&#xff0c;2024年4月9日/PRNewswire/-媒体和娱乐&#xff08;M&E&#xff09;行业人工智能技术解决方案的先驱Prime Focus Techn…

23种设计模式之代理模式

代理模式 1、概念 代理模式&#xff1a;给某一个对象提供一个代理或占位符&#xff0c;并由代理对象来控制对原对象的访问 代理模式是常用的结构型设计模式之一&#xff0c;在Java RMI、Web Service、Spring AOP等技术和框架中都使用了代理模式 2、代理模式结构 Subject&a…

[工具探索]英寸vs毫米下常见尺寸排版

文章目录 常见尺寸1. 照片尺寸2. 纸张尺寸3. 显示器和电视屏幕尺寸4. 手机屏幕尺寸5. 笔记本电脑屏幕尺寸6. 其他设备尺寸 换算公式换算方法常见照片尺寸对比表国际标准ISO&#xff08;216&#xff09;纸张尺寸 什么是英寸&#xff1f; 英寸&#xff08;英语&#xff1a;inch&a…

R语言统计分析——图形参数

参考资料&#xff1a;R语言实战【第2版】 我们可以通过修改图形参数来自定义一幅图形的多个特征&#xff08;字体、颜色、坐标轴、标签&#xff09;。一种方法是通过函数par()来指定这些参数&#xff0c;以这种方式设定的参数除非被再次修改&#xff0c;否则将会在会话结束前一…

webshell三巨头 综合分析(蚁剑,冰蝎,哥斯拉)

考点: 蚁剑,冰蝎,哥斯拉流量解密 存在3个shell 过滤器 http.request.full_uri contains "shell1.php" or http.response_for.uri contains "shell1.php" POST请求存在明文传输 ant 一般蚁剑执行命令 用垃圾字符在最开头填充 去掉垃圾字符直到可以正常bas…