Android 性能优化 UI优化

来源:互联网 发布:mysql获取当前时间 编辑:程序博客网 时间:2024/05/02 06:11

前言:

本篇文章主要学习UI性能优化。

1. 应用UI卡顿的原理

1.1 原理

用户感觉到卡顿的原理就是在渲染时出现了掉帧。Android系统要求 1s内渲染60帧,即渲染1帧必须要在16ms完成。如果你的界面没有在16ms内准备好一帧,所以就不会进行渲染,屏幕也就不会刷新。结果就是用户就是盯着一帧看了32ms,而不是16ms,因为刷新频率的不一致,就使用户感知到了卡顿。

1.2 为什么是60fps

官方出的性能优化视频Android Performance Patterns: Why 60fps? 解释说:

While 60 frames per second is actually the sweet pot. Great, smooth motion without all the tricks. And most humans can’t perceive the benefits of going higher than this number.
60fps是最恰当的帧率,是用户能感知到的最流畅的帧率,而且人眼和大脑之间的协作无法感知到超过 60fps的画面更新。

Now, it’s worth noting that the human eye is very discerning when it comes to inconsistencies in these frame rates
但值得注意的是人眼却能够感受到刷新频率不一致带来的卡顿现象,比如一会60fps,一会30fps,这是能够被感受到的,即卡顿。

As an app developer, your goal is clear. Keep your app at 60 frames per second. that’s means you have got 16 milliseconds per frame to do all of your work.That is input, computing, network and rendering every frame to stay fluid for your users.
所以作为开发者,你必须要保证你的所有操作在16ms内完成包括输入、计算、网络、渲染等这些操作,才能保证应用使用过程的流畅性。

在知道了卡顿是因为掉帧后,我们就来探讨引起掉帧的原因有哪些。

2. 导致卡顿的原因

  1. 布局Layout过于复杂,无法在16ms内完成渲染;
  2. View过度绘制,导致某些像素在同一帧时间内被绘制多次,从而使CPU或GPU负载过重;
  3. View频繁的触发measure、layout,导致measure、layout累计耗时过多及整个View频繁的重新渲染;
  4. 人为在UI线程中做轻微耗时操作,导致UI线程卡顿;
  5. 同一时间动画执行的次数过多,导致CPU或GPU负载过重;
  6. 内存频繁触发GC过多(同一帧中频繁创建内存),导致暂时阻塞渲染操作;
  7. 冗余资源及逻辑等导致加载和执行缓慢;
  8. 工作线程优先级未设置为Process.THREAD_PRIORITY_BACKGROUND导致后台线程抢占UI线程cpu时间片,阻塞渲染操作;
  9. ANR;

接下来就针对这些原因使用性能分析工具进行分析,并提出可能有效的解决方法。

3. 开启StrictMode

这是最简单的检测性能的方法,在Application中或者在开发者模式中开启即可。详情可查看: Android 性能优化 StrictMode使用

4. 减少布局复杂度

减少布局复杂度,可以从两个方面着手:一是优化相同层级结构时,二是多层级布局结构时尽量减少层级。

4.1 在相同层级结构相同并且界面效果相同时,选择性能高的ViewGroup

FrameLayout>LinearLayout>RelativeLayout,同时也可以自定义ViewGroup来减少计算量。

4.2 减少布局层次

the performance might improve by flattening the layout—make the layout shallow and wide, rather than narrow and deep.
扁平的布局可能比深层次的布局效率要高。这里可以通过HierarchyViewer.profileNode进行数据观察,并检测布局冗余。

The Hierarchy Viewer application allows you to debug and optimize your user interface. It provides a visual representation of the layout’s View hierarchy (the View Hierarchy window) with performance information for each node in the layout, and a magnified view of the display (the Pixel Perfect window) to closely examine the pixels in your layout.
使用Hierarchy Viewer可以调试和优化应用的UI界面。并提供了可视化的View层级垂直视图可以查看每个View节点的详细信息,并且可以在像素级别上检测你的布局。

官方文档:Optimizing Layout Hierarchies,Hierarchy Viewer

4.3 减少布局复杂度可行的方法:

  • 使用merge标签
    merge标签就是为减少布局层次而生的,它通过减少View树的层级来优化布局,而且可以减少过渡渲染,merge只能作为xml布局的根标签使用。
    如果在代码中Inflate带merge标签的布局时,必须为这个自定义View指定一个父ViewGroup,并且设置attachToRoot为true。

  • 使用ViewStub标签,Loading Views On Demand
    ViewStub是一个用于在运行时加载布局资源、不可见、宽高为0的View,在布局文件中使用它只是用于占位,在代码中没有手动加载它时,并不会影响页面的测量、绘制、显示效率,在代码中通过inflate加载ViewStub时,ViewStub会用在布局文件中为其指定的布局文件来代替它自身。ViewStub只能够被inflate一次,一旦加载后ViewStub对象就会被置为空,需要判空。ViewStub标签有对应的java类ViewStub.java。

5. 避免过渡绘制

通过开发者模式的 调试GPU过渡来开启GPU过度渲染,Visualize GPU Overdraw。

GPU过度绘制指的是在屏幕一个像素上绘制多次(超过一次)。
过渡绘制用于检测你的程序是否存在不必要的绘制,可以帮助开发者找出应用中过渡渲染的地方,减少不必要的过渡渲染以提高程序运行效率。

颜色 含义 无色 没被渲染的区域、WebView等的渲染区域 蓝色 1x过度绘制 绿色 2x过度绘制 淡红色 3x过度绘制 红色 4x(+)过度绘制



overdraw_options_view.png

应用无法完全做到没有过渡绘制,优化是尽量避免不必要的过渡绘制,通常情况下保证同一区域过渡绘制少于三次都是合理的,即只要是出现红色(淡红色和深红色)的地方,就是需要优化的地方。

官方文档:
Debug GPU Overdraw Walkthrough

减少过渡绘制可行的方法:

  • 去掉不必要的背景
    每个Activity都会在AndroidManifest.xml中设置主题,主题的目的是设置界面的显示风格,但在设置主题的时候通常情况下默认给Window设置了背景。Android系统在刷新整个界面时不仅仅是刷新Activity,还会刷新Window。
    如果默认没有去掉window的背景,并且在布局文件中给Activity设置了背景,就会存在过渡绘制的问题。

  • 使用Space标签
    Space标签可以只在布局文件中占位,不绘制,Space标签有对应的java类Space.java。
    Space类的draw()方法为空,即并不绘制本身,所以只做占位用,其颜色为transparent。

  • 自定义控件时canvas.clipRect可以解决只刷新固定区域的问题,可参考DrawerLayout。

  • 不必要的alpha值设置可以解决同一视图被多次绘制的问题;

6. 使用GPU呈现模式图

在开发者模式中开启Profile GPU Rendering查看。在机器上看到GPU绘制图形信息,分别展示了StatusBar、NavgationBar、Activity区域等的GPU渲染时间信息,随着界面的刷新,界面上会以实时柱状图来显示每帧的渲染时间,柱状图越高表示渲染时间越长,每个柱状图偏上都有一根代表16ms基准的绿色横线,只要我们每一帧的总时间低于基准线就不会发生UI卡顿问题。

通过该工具若有柱状图超过基准线,便说明有丢帧,此时可以结合traceview和systrace来定位问题。
6、7、8这三块都是解决掉帧问题,通过相关工具确认到具体代码位置,然后进行优化。

官方文档:
Profile GPU Rendering Walkthrough
Analyzing with Profile GPU Rendering

7. 使用Systrace:

  • The Systrace tool allows you to collect and inspect timing information across an entire Android device, which is called a trace. It shows where time and CPU cycles are being spent, displaying what each thread and process is doing at any given time.
    It also inpects the captured tracing information to highlight problems that it observes, from list item recycling to rendering content, and provide recommendations about how to fix them.
    Systrace允许你监视和跟踪Android系统的行为(trace)。它会告诉你系统都在哪些工作上花费时间、CPU周期都用在哪里,甚至你可以看到每个线程、进程在指定时间内都在干嘛。它同时还会突出观测到的问题,从垃圾回收到渲染内容都可能是问题对象,甚至提供给你建议的解决方案。

  • Systrace是Android4.1中新增的性能数据采样和分析工具。它可帮助开发者收集Android关键子系统(如surfaceflinger、WindowManagerService等Framework部分关键模块、服务)的运行信息,从而帮助开发者更直观的分析系统瓶颈,改进性能。Systrace的功能包括跟踪系统的I/O操作、内核工作队列、CPU负载以及Android各个子系统的运行状况等。

  • Systrace以Linux Kernel的ftrace为基础。

在mac上运行systrace.py时需要安装pyserial,我是通过anaconda安装。也可以直接通过DDMS使用systrace。

也可以通过命令行执行如下:

$ cd android-sdk/platform-tools/systrace$ python systrace.py --time=10 -o mynewtrace.html sched gfx view wm

10秒后生成的html文件通过chrome打开,使用 WASD和M键等快捷键来查看,基本可以完全看到所渲染每一帧所消耗的时间,并且在图表上提示了alert,点击便可查看它所提示的信息,进而确认问题,提升性能。

Analyzing UI Performance with Systrace
性能工具Systrace

8. 使用TraceView

TraceView 是 Android 平台特有的数据采集和分析工具,它主要用于分析 Android 中应用程序的 hotspot。TraceView 本身只是一个数据分析工具,而数据的采集则需要使用 Android SDK 中的 Debug 类或者利用 DDMS 工具。
TraceView是Android平台特有的数据采集和分析工具,它主要用于分析Android中应用程序的hotspot。让我们了解我们要跟踪的程序的性能,并且能具体到method。

  1. 可以通过DDMS进行数据采集,完成后会自动打开TraceView界面,便可进行分析。
  2. 使用代码Debug.startMethodTracing(),Debug.stopMethodTracing() 来生成.trace文件,pull到电脑上后再打开该文件。这种使用可一般放在Application类中onCreate()方法内以进行冷启动优化。

一般使用TraceView来分析两类问题:

  • 一类是调用次数不多,但每次调用却需要花费很长时间的函数。
  • 一类是那些自身占用时间不长,但调用却非常频繁的函数。

关于第一种,通常做法是先按Cpu Time/Call降序排序,然后看Incl Cpu Time的大小,综合起来越大的性能问题越严重。
关于第二种,通常做法是按Calls + Recur Calls/Total降序排序,然后看Incl Cpu Time的大小,综合起来越大的性能问题越严重

参数 参数解释 Incl Cpu Time 方法自身及该方法调用的所有子方法所占时间和 Excl Cpu Time 方法自身所占时间,但不含内部调用其它函数所占用的CPU时间 Incl Real Time 某函数运行的真实时间(以毫秒为单位),内含调用其它函数所占用的真实时间 Excl Real Time 某函数运行的真实时间(以毫秒为单位),不含调用其它函数所占用的真实时间 Call+Recur Calls/Total 某函数被调用次数以及递归调用占总调用次数的百分比 Cpu Time/Call 某函数调用CPU时间与调用次数的比。相当于该函数平均执行时间 Real Time/Call 同CPU Time/Call类似,只不过统计单位换成了真实时间


相关文章:
TraceView性能优化工具使用
Android 编程下的 TraceView 简介及其案例实战
Android 常用的性能分析工具详解:GPU呈现模式, TraceView, Systrace, HirearchyViewer
Android系统性能调优工具介绍

9. Use Lint

Android Lint is a static code scanning tool that helps you optimize the layouts and layout hierarchies of your applications, as well as detect other common coding problems.
Lint 是一个静态的代码扫描工具,可以帮助优化布局、布局层级和其他的一些问题。

Lint automatically runs whenever you compile your program. With Android Studio, you can also run lint inspections for a specific build variant, or for all build variants.
在Android Studio中可以在打开 Analyze > Inspect Code来检测问题。


结语:

本篇文章大概介绍了用于UI性能问题分析的工具,并没有列举其使用场景和怎么分析。关于工具,熟练使用还有待时日。另外,可以看看这篇文章 App优化之消除卡顿,这篇文章有大量的使用场景,而且通俗易懂。


参考:

  • 官方文档:
    Best Practices for Performance
    Performance Profiling Tools
  • 主要参考:
    Speed up your app 这篇主要是如何使用工具
    Android应用开发性能优化完全分析
    应用开发进阶必经之路之性能优化
    Android客户端性能优化
    Android的性能优化
    其他参考
    Android性能优化典范 - 第1季
    Android界面性能调优手册
1 0
原创粉丝点击