Android UI刷新机制与SurfaceView

这篇具有很好参考价值的文章主要介绍了Android UI刷新机制与SurfaceView。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

问题:

举例一个Activity的布局文件和逻辑如下:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical"
 tools:ignore="MissingDefaultResource"
 android:background="@android:color/holo_red_dark">

 <FrameLayout
     android:id="@+id/surfaceView_container"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_gravity="center"
     android:padding="10dp"
     android:background="@android:color/holo_blue_bright">

 <SurfaceView
     android:id="@+id/surfaceView"
     android:layout_gravity="center"
     android:layout_width="200dp"
     android:layout_height="200dp"></SurfaceView>

 <LinearLayout
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:layout_gravity="bottom"
     android:orientation="horizontal">

     <Button
         android:id="@+id/gone_btn"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="set container gone"></Button>


     <Button
         android:id="@+id/remove_btn"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="remove surfaceView"></Button>

 </LinearLayout>
 </FrameLayout>


</FrameLayout>

   container.findViewById(R.id.remove_btn).setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
             surfaceViewContainer.removeView(surface); //这个会回调到surfaceDestroyed, surfaceView立即就会消失,会出现黑块
             try {
                 Thread.sleep(10000);
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
     });

当我们点击remove_btn时,会出现SurfaceView所在的区域会出现10s黑块的现象,这个现象在我们平时开发中用到SurafceView时常常遇到,往往在主线程同时存在耗时操作和SurfaceView detach操作的时候出现,那么为什么Surfaceview从parent view上面detach的时候容易出现黑块现象呢?开发中遇到SUrfaceView黑块问题又该如何解决呢?下面对这两个问题进行讲解。

回答问题之前,我们先了解下Android 普通View的刷新流程和SurfaceView的刷新有什么区别。

VSync信号的产生:

关于页面渲染,我们经常关注的性能指标就是帧率,一般认为达到60 帧/秒 就可以骗过人眼,给人比较顺滑的视觉体验,在Android中有一个很重要的概念就是VSync信号,一般认为是16ms发送一次,Vsync机制的引入,主要有以下两个作用:

  • 提升UI刷新的优先级,使得UI刷新操作能够及时执行;

  • 在CPU、GPU和Display之间保持同步,减少Jank帧和屏幕渲染延迟。

Android UI刷新机制与SurfaceView

VSync信号由硬件产生,决定于显示器的扫描频率,硬件产生原始的VSync信号后,会被转化为两个VSync信号,一个用于通知APP层去刷新UI,一个用于通知SurfaceFlingger取graphic buffer组合处理后给显示屏显示。VSync信号分发流程如下:

Android UI刷新机制与SurfaceView

SurfaceFlinger:

SurfaceFlinger是系统进程,用于整合不同APP不同Window的图像,合成之后给硬件显示。

每一个Layer对应java层的Surface,即一个窗口,一个Activity对应一个Surface,一个WindowManager创建出来的小窗对应一个独立的Surface,SurfaceView比较特殊,尽管可以嵌入在Activity的布局中,但实际上它独占一个Surface;这个特性与本文最开始提出的问题息息相关,后文会继续分析。

Android UI刷新机制与SurfaceView

Android UI刷新机制与SurfaceView

基本流程如下:

Android UI刷新机制与SurfaceView

步骤1,2:CPU和GPU处理完之后将buffer放到BufferQueue,并调用onFrameAvailable通知SurfaceFlinger有可用buffer了。

步骤3:SurfaceFlinger再通过内部MessageQueue调用requestNextVsync请求接收下一个VSYNC用于合成。

步骤4,5:下一个VSYNC到了之后回调MessageQueue的handleMessage函数,实际调到SurfaceFlinger的onMessageReceived函数处理如下两种类型消息:

Android UI刷新机制与SurfaceView

步骤6,7:在处理REFRESH消息时最终会调用acquireBuffer函数从BufferQueue中将之前APP绘制完成的buffer取出来合成。

从上文可以看出,SurfaceFlinger的组合图层给硬件显示之前,需要先去取graphic buffer,那么graphic buffer又是谁去更新的呢?对于普通View和SurfaceView来说,这个机制会有所差别。

普通View刷新机制:

举例Activity中的一个TextView的更新如下:

如果应用层通过调用TextView的setText方法修改显示的文案,总体的执行流程如下:

Android UI刷新机制与SurfaceView

步骤描述:

  1. TextView调用setText方法,会执行到TextView的invalidate方法,这就会递归调用parent的invalidate,一直到ViewRootImpl类的invalidate方法,这个方法会调用到scheduleTraversals

  2. ViewRootImpl通过scheduleTraversals方法会调用到Choreographer的postCallback方法,postCallback会记录ViewRootImpl中的mTraversalRunnable,并向底层注册监听下一个vSync信号

  3. 底层的vSync信号过来之后,才会通过给主线程发送Runnable任务,执行Choreographer的doFrame方法,这里面真正调用执行ViewRootImpl中的doTraversal(包括performMeasure、performLayout、performDraw)流程

  4. draw的具体实现通过ThreadedRenderer类,调用到c++层的RenderThread,实现在render thread执行GPU计算,更新SurfaceFlinger中buffer 队列

  5. 下一次SurfaceFlinger收到Vsync信号的时候,就可以真正将这次setText的内容交给硬件,显示给用户了

因此,Android系统中普通View的渲染,并不是代码执行完立即显示到屏幕上的,而是需要在设置变化之后,等待消费下一次给APP的vSync信号,才能把新的图像更新给SurfaceFlinger,而后才能真正显示出来。

UI刷新通用流程总结如下:

Android UI刷新机制与SurfaceView

步骤1:View调用invalidate方法进行重绘时最终会递归调用到ViewRootImpl中。

步骤2: ViewRootImpl并不会立即会View进行绘制,而是调用scheduleTraversals将绘制请求给到Choreographer,并开始同步屏障,保证UI处理的高优先级。

步骤3,4: 通过postCallback将绘制请求给到Choreographer之后,Choreographer最终会将监听下一个VSYNC的请求发送到SurfaceFlinger进程的DispSync这个类,这是VSYNC分发的核心。

步骤5,6:当下一个VSYNC到来之后会回调Choreographer的onVsync方法,onVsync中调用doFrame,doCallbacks处理View的绘制请求。

步骤7:View绘制请求的入口即ViewRootImpl的performTraversals,这个方法会依次执行View的onMeasure,onLayout,onDraw开始View的绘制流程。

步骤8:硬件加速引入之后UI的具体绘制会在一个单独的渲染线程RenderThread,CPU为View构建DisplayList(包含绘制指令和数据)之后将数据共享给GPU,剩下的绘制操作由GPU在RenderThread线程完成。

步骤9,10,11:向BufferQueue中dequeue一块可用GraphicBuffer之后由GPU对这个块buffer进行操作,完成之后交换buffer(dequeue的是back buffer,front buffer用于显示,back buffer绘制完成之后和front buffer交换)。

步骤12:此时CPU和GPU对buffer的绘制已经完成(概念上已经完成,实际上GPU可能还在操作,依赖Fence进行同步),接着通过queueBuffer函数将buffer转移到BufferQueue,然后通知SurfaceFlinger有可用buffer了。

CPU、GPU、SurfaceFlinger如何协作:

Android UI刷新机制与SurfaceView

SurfaceView的刷新与销毁:

挖洞与绘制:

前面提到过,SurfaceView与普通的View有很大的区别,它可以嵌入到Activity的布局中,但是它是一个独立的Surface(Layer),内容的刷新流程也跟普通的View完全不一样。SurfaceView在Activity中的布局,只决定它的显示位置。如果没有设置setZOrderOnTop为true,SurfaceView的窗口在Activity窗口的下面,SurfaceView这个Layer的显示,依赖于ViewRootImpl中挖洞的逻辑(gatherTransparentRegion),在ViewRootImpl类中performLayout逻辑执行完之后,会收集SurfaceView需要透出的区域,并把这个信息传递给底层,将这个区域设置为透明,这样Actvity这一层的Layer就不会遮挡下面SurfaceView的Layer。

Android UI刷新机制与SurfaceView

image.jpeg

挖洞流程如下:

Android UI刷新机制与SurfaceView

SurfaceView支持在后台线程直接绘制内容,基本绘制流程如下,调用了unlockCanvasAndPost之后,便会将在Canvas上绘制的内容通过独立的RenderProxy处理后提交给SurfaceFlinger合成,后面就可显示出来了。也可以通过holder.getSurface()获取到Surface之后,直接通过OpenGl渲染。

Android UI刷新机制与SurfaceView

销毁:

这里讲SurfaceView的销毁主要指的是将SurfaceView对应的Layer从SurfaceFlinger中移除。一般可以通过直接设置这个SurfaceView本身不可见(注意设置这个SurfaceView的父View不可见不会触发Layer的移除)或者将这个SurfaceView从ViewTree上remove掉实现。如VC中使用的是从父View remove这个SurfaceView的方法实现SurfaceView资源的释放和视图的刷新。

当调用parent.removeView将SurfaceView移除时,流程如下:

Android UI刷新机制与SurfaceView

可以看出,当SurfaceView被从父View上remove掉时,是直接调用代码,将自己对应的Layer从的SurfaceFlinger中移除掉了。并不像普通的View更新一样,需要等待下一个vSync信号,在主线程插入Runnable任务触发doTraversal的流程,然后再将这个变化反应给SurfaceFlinger。

回到文初的问题:

结合前面的调用流程,可以知道,在refreshAllUnit的过程中,由于这个方法总体耗时较长,并且在主线程执行,这期间Choreographer没办法插入任务去执行doTraversal的流程,因此Activity对应的代码执行了,但实际上并没有更新显示。而SurfaceView被remove掉之后,会直接更新显示,这中间就有一个时间差,导致SurfaceView原来显示的区域出现了黑块(挖出来的洞)。

Android UI刷新机制与SurfaceView

那么如何解决SurfaceView黑块的问题呢?我们可以在调用SurfaceView的detach方法之前,插入16ms的延时,先让SurfaceView的parent视图区域变得不可见,切换为新的视图成功之后,再调用SurfaceView的detach方法。

最后

要想成为架构师,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。
Android UI刷新机制与SurfaceView
相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

一、架构师筑基必备技能

1、深入理解Java泛型
2、注解深入浅出
3、并发编程
4、数据传输与序列化
5、Java虚拟机原理
6、高效IO
……

Android UI刷新机制与SurfaceView

二、Android百大框架源码解析

1.Retrofit 2.0源码解析
2.Okhttp3源码解析
3.ButterKnife源码解析
4.MPAndroidChart 源码解析
5.Glide源码解析
6.Leakcanary 源码解析
7.Universal-lmage-Loader源码解析
8.EventBus 3.0源码解析
9.zxing源码分析
10.Picasso源码解析
11.LottieAndroid使用详解及源码解析
12.Fresco 源码分析——图片加载流程

Android UI刷新机制与SurfaceView

三、Android性能优化实战解析

  • 腾讯Bugly:对字符串匹配算法的一点理解
  • 爱奇艺:安卓APP崩溃捕获方案——xCrash
  • 字节跳动:深入理解Gradle框架之一:Plugin, Extension, buildSrc
  • 百度APP技术:Android H5首屏优化实践
  • 支付宝客户端架构解析:Android 客户端启动速度优化之「垃圾回收」
  • 携程:从智行 Android 项目看组件化架构实践
  • 网易新闻构建优化:如何让你的构建速度“势如闪电”?

Android UI刷新机制与SurfaceView

四、高级kotlin强化实战

1、Kotlin入门教程
2、Kotlin 实战避坑指南
3、项目实战《Kotlin Jetpack 实战》

  • 从一个膜拜大神的 Demo 开始

  • Kotlin 写 Gradle 脚本是一种什么体验?

  • Kotlin 编程的三重境界

  • Kotlin 高阶函数

  • Kotlin 泛型

  • Kotlin 扩展

  • Kotlin 委托

  • 协程“不为人知”的调试技巧

  • 图解协程:suspend

Android UI刷新机制与SurfaceView

五、Android高级UI开源框架进阶解密

1.SmartRefreshLayout的使用
2.Android之PullToRefresh控件源码解析
3.Android-PullToRefresh下拉刷新库基本用法
4.LoadSir-高效易用的加载反馈页管理框架
5.Android通用LoadingView加载框架详解
6.MPAndroidChart实现LineChart(折线图)
7.hellocharts-android使用指南
8.SmartTable使用指南
9.开源项目android-uitableview介绍
10.ExcelPanel 使用指南
11.Android开源项目SlidingMenu深切解析
12.MaterialDrawer使用指南
Android UI刷新机制与SurfaceView

六、NDK模块开发

1、NDK 模块开发
2、JNI 模块
3、Native 开发工具
4、Linux 编程
5、底层图片处理
6、音视频开发
7、机器学习

Android UI刷新机制与SurfaceView

七、Flutter技术进阶

1、Flutter跨平台开发概述
2、Windows中Flutter开发环境搭建
3、编写你的第一个Flutter APP
4、Flutter开发环境搭建和调试
5、Dart语法篇之基础语法(一)
6、Dart语法篇之集合的使用与源码解析(二)
7、Dart语法篇之集合操作符函数与源码分析(三)

Android UI刷新机制与SurfaceView

八、微信小程序开发

1、小程序概述及入门
2、小程序UI开发
3、API操作
4、购物商场项目实战……

Android UI刷新机制与SurfaceView

全套视频资料:

一、面试合集
Android UI刷新机制与SurfaceView
二、源码解析合集

Android UI刷新机制与SurfaceView
三、开源框架合集

Android UI刷新机制与SurfaceView
欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证微信卡片领取【保证100%免费】↓↓↓
Android UI刷新机制与SurfaceView文章来源地址https://www.toymoban.com/news/detail-401587.html

到了这里,关于Android UI刷新机制与SurfaceView的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android MediaPlayer+SurfaceView+自定义控制器实现视频播放

    Android提供了多种视频播放的方式,如下: 1、MediaController+VideoView实现方式 这种方式是最简单的实现方式。VideoView继承了SurfaceView同时实现了MediaPlayerControl接口,MediaController则是安卓封装的辅助控制器,带有暂停,播放,停止,进度条等控件。通过VideoView+MediaController可以很轻

    2024年02月04日
    浏览(38)
  • Android 使用OpenCV实现实时人脸识别,并绘制到SurfaceView上

    上篇文章 我们已经通过一个简单的例子,在 Android Studio 中接入了 OpenCV 。 之前我们也 在Visual Studio上,使用OpenCV实现人脸识别 中实现了人脸识别的效果。 接着,我们就可以将 OpenCV 的人脸识别效果移植到 Android 中了。 1.1 环境说明 操作系统 : windows 10 64 位 Android Studio 版本

    2024年02月10日
    浏览(53)
  • 高级UI之Android事件分发机制原理及源码分析

    在 Android 中, 事件分发机制是一块很重要的知识点, 掌握这个机制能帮你在平时的开发中解决掉很多的 View 事件冲突问题,这个问题也是面试中问的比较多的一个问题了, 本篇就来总结下这个知识点。 Android 中页面上的 View 是以树型结构显示的,View 会重叠在一起,当我们

    2024年02月08日
    浏览(43)
  • 使用adb命令获取Android SurfaceView 的 帧率(fps)jank,手机的基本信息

            adb shell dumpsys SurfaceFlinger | grep + 包名启动页 (不然他获取的数据是只有一行数据),这个命令只需要执行一次         使用的是adb shell dumpsys SurfaceFlinger --latency \\\"SurfaceView +包名/启动页\\\"获取的,目前只支持安卓6.0以上。         使用adb 命令时,可以根据他的

    2023年04月19日
    浏览(47)
  • Android-高级-UI-进阶之路-(二)-深入理解-Android-8-0-View-触摸事件分发机制,查漏补缺

    我们看到内部又调用了父类 dispatchTouchEvent 方法, 所以最终是交给 ViewGroup 顶级 View 来处理分发了。 顶级 View 对点击事件的分发过程 在上一小节中我们知道了一个事件的传递流程,这里我们就大致在回顾一下。首先点击事件到达顶级 ViewGroup 之后,会调用自身的 dispatchTouchE

    2024年04月14日
    浏览(71)
  • 无感刷新:Vue前端实现Token的无缝刷新机制

    在现代Web应用程序中,用户身份验证和授权通常使用令牌(Token)机制来实现。然而,由于Token的过期时间限制,用户在长时间使用应用程序时可能需要重新登录。为了提供更好的用户体验,我们可以通过实现Token的无感刷新机制来避免用户在使用过程中的中断。本文将探讨如

    2024年02月10日
    浏览(40)
  • Vsync信号和SurfaceFlinger刷新机制;打造智能车厢的关键技术

    车载智能座舱系统在现代汽车中已经越来越常见,它可以提供各种功能,例如音乐、导航和驾驶辅助等。要实现这些功能,需要底层硬件和系统软件的支持。其中,Vsync信号和SurfaceFlinger刷新机制是车载智能座舱系统中的两个关键技术。 Vsync信号是指显示器垂直同步信号,它可

    2023年04月23日
    浏览(34)
  • redis发布订阅广播模式的使用&结合jeecg的Redis网关路由刷新机制

    本质和传统的消息发布和订阅机制是差不多的,但是相较于其他几款MQ产品,Redis的使用更加便捷,也更加轻量化,不需要搭建一套繁重的MQ框架。 但是也它致命的缺点,redis的消息不会被持久化,服务器出现问题,消息会丢失,导致数据问题。对于数据一致性要求比较高的场

    2023年04月20日
    浏览(80)
  • PyQt5 多线程和异步刷新UI

    以下简介一个基本的PyQt程序。 需要导入的类主要来自三个包 from PyQt5.QtWidgets import 常用的控件 PyQt5.QtCore 核心功能类,如QT,QThread,pyqtSignal PyQt5.QtGui UI类,如QFont 基础的程序结构: 注意: 使用join方法会让主线程阻塞在这里,等待子线程结束,在里面可以设置阻塞的时间 a

    2024年02月11日
    浏览(41)
  • element-ui 分页刷新无效问题

    问题:在列表页跳转至详情页,再从详情页回到列表,分页列表停留在第一页,数据不刷新问题。 先设置设置当前的页码绑定 current-page.sync=\\\"page\\\" 给分页组件设置v-if=\\\"showPage\\\" 3.在data里面设置 showPage为ture 4.在点击切换分页方法时,先设置this.showPage = false;再使用 $nextTick回调方

    2024年02月13日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包