IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 卡顿优化小结 -> 正文阅读

[移动开发]卡顿优化小结

卡顿

理解卡顿

先理解个概念:帧数。帧数就是在1秒时间里传输的图片的量,也可以理解为图形处理器每秒钟能够刷新几次,通常用FPS表示。每一帧其实就是静止的图像,通过快速连续显示帧便形成了运动的假象。要想画面保持在60fps,需要屏幕在1秒内刷新60 次,也就是每16ms刷新一次,绘制时长在16ms以内。
在这里插入图片描述
Android 系统每隔16ms发出VSYNC信号,触发UI进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需要60fps。

VSYNC 是 Vertical Synchronization (垂直同步)的缩写,是一种定时中断,一旦收到VSYNC信号,CPU就开始处理各种帧数据,CPU就开始处理各帧数据。如果某个操作要花费24ms,这样系统在得到VSYNC信号时无法进行正常的渲染,会发生丢帧。用户会在32ms中看同一帧的画面。
在这里插入图片描述
这种丢帧的情况对用户来说,表现出来就是卡顿

一帧渲染生成过程

在这里插入图片描述

卡顿检测工具

Systrace

Systrace 是 Android4.1 中新增的性能数据采样和分析工具。它可帮助开发者收集 Android 关键子系统(如 SurfaceFlinger/SystemServer/Kernel/Input/Display 等 Framework 部分关键模块、服务,View系统等)的运行信息,从而帮助开发者更直观的分析系统瓶颈,改进性能。

Systrace 的功能包括跟踪系统的I/O操作、内核工作队列、CPU 负载以及 Android各个子系统的运行状况等。具体使用请看这篇文章Android 系统分析工具:Systrace

System Trace

Android 9或更高版本的设备包含一个名为 System Tracing的系统级应用。允许您直接从测试设备本身录制跟踪记录,而无需插入设备并通过 ADB 连接到该设备。解决应用中与性能相关的错误(例如启动速度慢、转换速度慢或界面卡顿)时,录制跟踪记录特别有用。 具体使用请看这篇文章性能分析工具System Trace

CPU Profiler

使用Android Studio集成Profiler中CPU性能剖析器可以监测页面卡顿的功能。具体使用请看这篇文章Android Studio Profiler CPU检测卡顿

Matrix-TraceCanary

Matrix是腾讯开源的APM性能优化框架,其中TraceCanary具有监测页面卡顿功能。TraceCanary分为帧率监控、慢方法监控、ANR监控以及启动耗时这4个功能。这些功能基本都需要插桩去trace过程中每个函数的调用。 在插桩之外,我们还需要监控主线程MessageQueue(LooperMonitor)以及Choreographer(UIThreadMonitor),从里面抽象出一个可以通知Message开始执行、执行完成、Choreographer开始渲染的接口(LooperObserver)。

具体使用请看这篇文章性能检测工具:Matrix-TraceCanary 入门

常见的卡顿来源

可滚动列表

ListView 和 RecyclerView(尤其是后者)常用于最易出现卡顿的复杂滚动列表。它们都包含Systrace标记,因此您可以使用Systrace来判断它们是不是导致应用出现卡顿的因素。请务必传递命令行参数 -a ,以便让RecyclerView中的跟踪部分(以及您添加的所有跟踪标记)显示出来。

卡顿场景1:使用RecyclerView的notifyDataSetChanged

如果您在一个帧中看到RecyclerView中的每一项都重新绑定(并因此重新布局和重新绘制),请确保您没有调用 notifyDataSetChanged()、setAdapter(Adapter) 或 swapAdapter(Adapter,boolean)来进行细微更新。这些方法会向系统表明整个列表内容已更改,并会在 Systrace 中显示为 RV FullInvalidate。应改用 SortedListDiffUtil,以便在内容发生更改或添加了内容时生成最少量的更新。

卡顿场景2:RecyclerView列表中嵌套横向滚动RecyclerView

由水平滚动列表组成的纵向列表的场景。在首次向下滚动页面时,如果您看到大量内部内容出现扩充,则可能需要检查内部(水平)RecyclerView 之间是否正在共享 RecyclerView.RecycledViewPool。默认情况下,每个 RecyclerView 都将有自己的内容池。然而,在屏幕上同时显示十几个 itemViews 的情况下,如果所有行都显示类型相似的视图,那么当不同的水平列表无法共享 itemViews 时,就会出现问题。

class OuterAdapter extends RecyclerView.Adapter<OuterAdapter.ViewHolder> {
        RecyclerView.RecycledViewPool sharedPool = new RecyclerView.RecycledViewPool();

        ...

        @Override
        public void onCreateViewHolder(ViewGroup parent, int viewType) {
           
            LinearLayoutManager innerLLM = new LinearLayoutManager(parent.getContext(),
                    LinearLayoutManager.HORIZONTAL);
            innerRv.setLayoutManager(innerLLM);
            // 使用RecycledViewPool() 方法
            innerRv.setRecycledViewPool(sharedPool);
            return new OuterAdapter.ViewHolder(innerRv);

        }
        ...
    

卡顿场景3:RecyclerView膨胀过多/创建过程用时过长

经常在屏幕上出现新内容时看到导致卡顿的扩充问题,请确认您的视图类型数量没有超出所需要的数量。RecyclerView内容中的视图类型越少,屏幕上出现新的内容类型时需要进行的扩充就越少。如果可能的话,可以在适当情况下合并视图类型:如果不同类型之间只有图标、颜色或文本片段不同,您可以在绑定时进行这项更改,从而避免膨胀(同时减少应用占用的内存)

减少不必要的容器和结构视图会有所帮助:请考虑使用ConstraintLayout构建 itemViews,以便轻松减少结构视图

卡顿场景4:RecyclerView绑定用时过长

onBindViewHolder(VH, int)方法里所有内容(最复杂的内容除外)所需的绑定时间都应远远少于 1 毫秒。它应该只从适配器的内部内容数据获取 POJO 内容,并对 ViewHolder 中的视图调用 setter。如果 RV OnBindView 用时很长,请确认在绑定代码中只执行最少量的工作。

卡顿场景5:RecyclerView 或 ListView:布局 / 绘制用时过长

布局性能

如果 Systrace 表明 Choreographer#doFrame 的布局部分执行的工作过多或者执行工作的频率太高,则意味着您遇到了布局性能问题。

优化地方1:开销

如果这些部分的用时超过几毫秒,您可能遇到了对 RelativeLayouts 或 weighted-LinearLayouts 来说最糟糕的嵌套性能。请尝试在层次结构的所有叶节点(最低叶节点除外)中避免使用 RelativeLayout,或避免使用 LinearLayout 的权重功能。解决方式:

  • 调整结构视图的组织方式。
  • 定义自定义布局逻辑(使用merge、include、ViewStub)。
  • 尝试转换为 ConstraintLayout,该布局提供类似的功能,但不存在性能缺陷。

优化地方2:频率

屏幕上出现新内容时,例如当新内容滚动到到RecyclerView中的视图上时,应该会进行布局。如果每帧都进行明显布局,则可能是在为布局呈现动画效果,这很可能会导致丢帧。一般来说,动画应以View的绘制属性(例如setTranslationX/Y/Z()、setRotation()、setAlpha()等等)运行。与布局属性(例如,内边距或外边距)相比,这些属性的更改开销要低得多。

渲染性能

Android 界面工作分为两个阶段:界面线程(UI 线程) 上的 Record View#draw(监控View 绘制)RenderThread(渲染线程) 上的 DrawFrame。第一阶段对每个失效的View运行draw(Canvas),并可调用自定义视图或代码。第二阶段在原生 RenderThread 上运行,但将根据 Record View#draw 阶段生成的工作运行。

检测地方1:界面线程(UI 线程)

如果 Record View#draw需要很长时间,通常情况下会在界面线程上绘制位图。绘制到位图时使用的是 CPU 呈现,因此通常应尽量避免此操作。结合使用System Trace 和CPU Profiler 监测卡顿工具。

检测地方2:RenderThread(渲染线程)

有些画布操作虽然记录开销很低,但会在RenderThread上触发开销非常大的计算。Systrace 通常会通过提醒来调用这些操作。

  • 避免 Canvas.saveLayer()

它可能会触发以开销非常大且未缓存的屏幕外方式呈现每帧。最好尽可能避免使用这个开销非常大的 API,或者至少确保传递Canvas.CLIP_TO_LAYER_SAVE_FLAG(或调用不带标记的变体)。

  • 为大型路径添加动画效果

对传递至视图的硬件加速画布调用 Canvas.drawPath() 时,Android 会首先在 CPU 上绘制这些路径,然后将它们上传到GPU。如果路径较大,请避免逐帧修改,以便高效地对其进行缓存和绘制。drawPoints()、drawLines() 和 drawRect/Circle/Oval/RoundRect() 的效率更高。

  • Canvas.clipPath

clipPath(Path) 会触发开销非常大的裁剪行为,因此通常应避免使用它。如果可能,请选择使用绘制形状,而不是裁剪为非矩形。它的效果更好,并支持抗锯齿功能。

举例: clipPath 调用

    canvas.save();
    canvas.clipPath(circlePath);
    canvas.drawBitmap(bitmap, 0f, 0f, paint);
    canvas.restore();
    改为:
    // one time init:
    paint.setShader(new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP));
    // at draw time:
    canvas.drawPath(circlePath, mPaint);

线程调度延迟

线程调度程序在Android操作系统中负责确定系统中的哪些线程应该运行、何时运行以及运行多长时间。有时,出现卡顿是因为应用的界面线程处于阻塞或未运行状态。
在这里插入图片描述
Systrace使用不同的颜色(如上图所示)来指明线程何时处于休眠状态(灰色)、可运行(蓝色:可以运行,但调度程序尚未选择让它运行)、正在运行(绿色)或处于不可中断休眠状态(红色或橙色)。这对于调试由线程调度延迟引起的卡顿问题非常有用。

对象分配和垃圾收集

Systrace 会显示GC是否频繁运行,而Android Memory Profiler 可显示分配来源。如果尽可能避免分配(尤其是在紧密循环中),则应该不会遇到问题。显示 HeapTaskDaemon 线程上的GC,如下图所示:
在这里插入图片描述
GC 通常在名为 HeapTaskDaemon的后台线程上运行。请注意,大量的分配可能意味着在 GC 上耗费更多的 CPU 资源。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-04-15 00:12:54  更:2022-04-15 00:14:40 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 20:38:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码