说到绘制优化,首先不得不提的就是绘制原理。我们知道,View的绘制流程有3个步骤,分别是measure、layout和draw,它们主要是运行在系统的应用框架层,而在底层则是由CPU来进行Measure、Layout、Record、Execute的数据计算工作,由GPU来进行栅格化、渲染。CPU和GPU通过共同操作图形驱动层维护的一个队列来完成绘制,即CPU将display list添加到该队列中,GPU从队列中取出数据进行绘制。
再来说说帧数,我们知道,画面在60fps时候不会感受到卡顿,如果低于60fps则会感受到卡顿,因此若要保持流畅,则屏幕需要在1秒内刷新60次,也就是说,需要将View绘制时长控制在16ms以内。
Android系统每隔16ms发出一种定时中断信号来触发对UI进行渲染。如果每次渲染都成功,就能够达到流畅画面的60fps,但是如果某个操作需要花费更多时间,那么在得到信号时就无法进行征程的渲染,这样就会发生丢帧现象。
产生卡顿的原因主要有以下几点:
①布局Layout过于复杂,无法在16ms内完成渲染;
②同一时间动画执行的次数过多,导致CPU或GPU负载过重;
③View过度绘制,导致某些像素在同一时间内被绘制多次;
④在UI线程中做了稍微耗时的操作;
⑤GC回收时暂停时间过长或者频繁的GC产生大量的暂停时间。
在Android4.1以上的设备中,以魅族Flyme8.1.5.0A为例(底层为Android9),在开发者选项中找到“监控”,将GPU渲染模式分析设为“在屏幕上显示为条形图”,这时候就会在屏幕出现彩色的柱状图,如下图所示:
对于每个可见应用,都将会显示一个图形。图中沿水平轴的每个竖条代表一个帧,每个竖条的高度表示渲染该帧所花的时间(以毫秒为单位),水平绿线表示 16 毫秒。要实现每秒 60 帧,代表每个帧的竖条需要保持在此线以下,当竖条超出此线时,可能会使动画出现暂停。
下表介绍了使用运行 Android 6.0 及更高版本的设备时分析器输出中某个竖条的每个区段(来源:Android开发者官网)。
4.0(API 级别 14)和 5.0(API 级别 21)之间的 Android 版本具有蓝色、紫色、红色和橙色区段。低于 4.0 的 Android 版本只有蓝色、红色和橙色区段。下表显示的是 Android 4.0 和 5.0 中的竖条区段。
共同都有的是橙色、红色以及蓝色。
“系统跟踪”就是记录短时间内的设备活动。系统跟踪会生成跟踪文件,该文件可用于生成系统报告,对于UI显示性能,比如动画播放不流畅、渲染卡顿等问题提供了分析数据。
“系统跟踪”应用是一款用于将设备活动保存到跟踪文件的 Android 工具。在搭载 Android 10(API 级别 29)或更高版本的设备上,跟踪文件会以 Perfetto 格式保存;在搭载较低版本 Android 系统的设备上,跟踪文件会以 Systrace 格式保存。
Systrace 是平台提供的旧版命令行工具,可记录短时间内的设备活动,并保存在压缩的文本文件中。该工具会生成一份报告,其中汇总了 Android 内核中的数据,例如 CPU 调度程序、磁盘活动和应用线程。systace对检测应用UI表现非常有效,因为它可以分析代码和帧率来识别出问题区域,然后提出可能的解决方案。
Perfetto 是 Android 10 中引入的全新平台级跟踪工具。这是适用于 Android、Linux 和 Chrome 的更加通用和复杂的开源跟踪项目。与 Systrace 不同,它提供数据源超集,可以以 protobuf 编码的二进制流形式记录任意长度的跟踪记录。
Perfetto 和 Systrace 可交互使用。
由于目前使用Android 10以下的手机还很多,这里就以Systrace为例进行说明。操作步骤如下:
①从Android Studio下载并安装最新的Android SDK工具(可依次点击 Tools > SDK Manager进入 SDK Manager进行查看)。
②安装Python(https://www.python.org/)(由于脚本仅支持2.X版本,请下载2.7版本)并将其添加到工作站的PATH环境变量中,如下图所示:
然后安装pywin32模块,可以使用pip命令进行安装。
③将android-sdk/platform-tools/添加到PATH环境变量。此目录包含由systrace程序调用的Android调试桥二进制文件 (adb)(systrace 命令在 Android SDK 工具软件包中提供,并且可以在 android-sdk/platform-tools/systrace/ 中找到)。
④使用 USB 调试连接将搭载Android 4.3(API 级别 18)或更高版本的设备连接到开发系统。
⑤使用以下语法通过命令行运行 systrace来为应用生成 HTML 报告:
python systrace.py [options] [categories]
例如,以下命令会调用systrace来记录设备活动,并生成一个名为mynewtrace.html的HTML报告。
python systrace.py -o mynewtrace.html sched freq idle am wm gfx view \
binder_driver hal dalvik camera input res
可以运行以下命令来查看已连接设备支持的类别列表:
python systrace.py --list-categories
如果未指定任何类别或选项,systrace会生成包含所有可用类别的报告,并使用默认设置。
⑥使用Chrome打开mynewtrace.html文件进行分析。报告界面如下图所示:
我们可以使用W键和S键进行放大和缩小;使用A键和D键进行左右移动。
接下来我们来具体讲解下这个报告怎么看。
整体观察,可以看见页面被分为了四部分,从上到下分别是用户互动、CPU 活动、应用区域以及Alert区域。接下来就分别说下这四个部分。
下面是systrace对每一种警告类型的解释:
Scheduling delay:渲染一帧的工作被推迟了几个毫秒,从而导致了不合格。确保UI线程上的代码不会被其他线程上完成的工作阻塞,并且后台线程(例如,网络或位图加载)在android.os.Process#THREAD_PRIORITY_BACKGROUND中运行或更低,因此它们不太可能中断UI线程。
Expensive measure/layout pass:测量/布局花费了很长时间,导致掉帧,要避免在动画过程中触发重新布局。
Long View#draw():记录无效的绘图命令花费了很长时间,在View或Drawable自定义视图时,要避免做耗时操作,尤其是Bitmap的分配和绘制。
Expensive Bitmap uploads:修改或新创建Bitmap视图要传送给GPU,如果像素总数很大,这个操作会很耗时。因此在每一帧中要尽量减少Bitmap变更的次数。
Inefficient View alpha usage:将alpha设置为半透明值(0
在Android Studio 3.2之前,一般会使用Traceview,但是由于Traceview日志记录无法很好地处理线程(如果线程在分析期间退出,不会发出线程名称(在 Android 5.1 及更高版本中已解决此问题);虚拟机会重复使用线程 ID。如果在一个线程停止时另一线程开始,这两个线程可能会获得同一 ID),所以已经在Android Studio 3.2中被弃用,取而代之的是CPU 性能剖析器。
CPU 性能剖析器不仅能够以图形的形式显示跟踪日志,更包含了Systrace的工作,因此,在Android Studio 3.2以后就可以使用CPU 性能剖析器完成这两项工作了。
我们接着Systrace的工作来做,生成一个跟踪日志。
如果在开发过程中出现不好复现的问题,可以在代码中添加跟踪语句,如下所示:
// Starts recording a trace log with the name you provide. For example, the
// following code tells the system to start recording a .trace file to the
// device with the name "sample.trace".
Debug.startMethodTracing("sample");
...
// The system begins buffering the generated trace data, until your
// application calls stopMethodTracing()
, at which time it writes
// the buffered data to the output file.
Debug.stopMethodTracing();
在开始监控的地方调用startMethodTracing方法,在需要结束的地方调用stopMethodTracing方法,系统就会在~/sdcard/ 目录中生成trace文件,这个文件包含二进制方法跟踪数据,以及一个包含线程和方法名称的映射表。在进行跟踪的时候不要忘了在AndroidManifest.xml中个加入
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
权限。
我们来举个例子进行详细说明。
public class TraceSampleActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_trace_sample);
//开始跟踪,并且指定生成名为sample的.trace文件
Debug.startMethodTracing("sample");
initView();
}
private void initView(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
protected void onStop() {
super.onStop();
//结束监控
Debug.stopMethodTracing();
}
}
我们使用了一个简单的例子来生成trace文件,然后将这个文件导出到桌面。这个trace文件的位置如下图所示:
①打开 CPU 性能剖析器:依次选择 View > Tool Windows > Profiler 或点击工具栏中的 Profile 图标 。
②在性能剖析器的 Sessions 窗格中点击 Start new profiler session 图标 ,然后选择 Load from file。
可以看到分为了两部分,分别是左面的时间片面板和右面的分析面板。
时间面板放大,之后将鼠标指针悬停在某个线程上,可以看见更详细的信息。
一般我们会查看色块的长度,然后对明显比较长的方法重点去关注。单击色块可以在右面的分析面板查看具体分析。
更详细的操作可以查看谷歌开发者文档:
在Android Studio 3.1之前,一般会使用Hierarchy Viewer分析布局,但是在Android Studio 3.1开始,Hierarchy Viewer则被弃用,改为了布局检查器和布局验证工具。
使用Android Studio中的布局检查器,可以将应用布局与设计模型进行比较、显示应用的放大视图或3D视图,以及在运行时检查应用布局的细节。如果布局是在运行时(而不是完全在XML中)构建的并且布局行为出现异常,该工具会非常有用。
使用布局验证,可以在不同的设备和显示配置(包括可变字体大小或用户语言)上同时预览布局,以便轻松测试各种常见的布局问题。