Android绘制优化(一)绘制性能分析

前言

一个优秀的应用不仅仅是要有吸引人的功能和交互,同时在性能上也有很高的要求。运行Android系统的手机,虽然配置在不断的提升,但仍旧无法和PC相比,无法做到PC那样拥有超大的内存以及高性能的CPU,因此在开发Android应用程序时也不可能无限制的使用CPU和内存,如果对CPU和内存使用不当也会造成应用的卡顿和内存溢出等问题。因此,应用的性能优化对于开发人员有着更高的要求。Android性能优化分为很多种,比较常用的有绘制优化、内存优化、耗电优化和稳定性优化等,这个系列我们就来学习性能优化中的绘制优化。

1.绘制原理

Android绘制View有三个主要的步骤,分别是measure、layout和draw。关于它们的原理请查看我的文章Android View体系(七)从源码解析View的measure流程Android View体系(八)从源码解析View的layout和draw流程,这里就不在赘述。measure、layout和draw方法主要是运行在系统的应用框架层,而真正将数据渲染到屏幕上的则是系统Nativie层的SurfaceFlinger服务来完成的。

绘制过程主要是由CPU 来进行Measure、Layout、Record、Execute的数据计算工作,GPU负责栅格化、渲染。CPU和GPU是通过图形驱动层来进行连接的。图形驱动层维护了一个队列,CPU将display list添加到该队列中,这样GPU就可以从这个队列中取出数据进行绘制。

渲染时间线

FPS(Frames Per Second)这个名词我想很多同学都知道,它是指画面每秒传输帧数,通俗来讲就是指动画或视频的画面数,最简单的举例就是我们玩游戏时,如果画面在60fps则不会感觉到卡顿,如果低于60fps,比如50fps则会感觉到卡顿,你就可以考虑要换显卡或者采取其他一些措施了。

要想画面保持在60fps,则需要每个绘制时长在16ms以内,如下图所示。

Android系统每隔16ms发出VSYNC信号,触发对UI进行渲染, 如果每次渲染都成功,这样就能够达到流畅的画面所需要的60fps,那什么是VSYNC呢?VSYNC是Vertical Synchronization(垂直同步)的缩写,是一种定时中断,一旦收到VSYNC信号,CPU就开始处理各帧数据。

如果某个操作要花费24ms,这样系统在得到VSYNC信号时无法进行正常的渲染,会发生丢帧。用户会在32ms中看到同一帧的画面,如下图所示。

产生卡顿原因有很多,主要有以下几点:

- 布局Layout过于复杂,无法在16ms内完成渲染。

- 同一时间动画执行的次数过多,导致CPU或GPU负载过重。

- View过度绘制,导致某些像素在同一帧时间内被绘制多次。

- UI线程中做了稍微耗时的操作。

为了解决上述的问题,除了我们要在写代码时要注意外,也可以借助一些工具来分析和解决卡顿问题。

2.Profile GPU Rendering

Profile GPU Rendering是Android 4.1系统提供的开发辅助功能,我们可以在开发者选项中打开这一功能,如下图所示。

我们点击Profile GPU Rendering选项并选择On screen as bars即开启Profile GPU Rendering功能。接着屏幕会显示出彩色的柱状图,如下所示。

上面的彩色的图的横轴代表时间,纵轴表示某一帧的耗时。绿色的横线为警戒线,超过这条线则意味着时长超过了16m,尽量要保证垂直的彩色柱状图保持在绿线下面。这些垂直的彩色柱状图代表着一帧,不同颜色的彩色柱状图代表不同的含义:

  • 橙色代表处理的时间,是CPU告诉GPU渲染一帧的地方,这是一个阻塞调用,因为CPU会一直等待GPU发出接到命令的回复,如果橙色柱状图很高,则表明GPU很繁忙。
  • 红色代表执行的时间,这部分是Android进行2D渲染 Display List的时间。如果红色柱状图很高,可能是由重新提交了视图而导致的。还有复杂的自定义View也会导致红的柱状图变高。
  • 蓝色代表测量绘制的时间,也就是需要多长时间去创建和更新DisplayList。如果蓝色柱状图很高,可能是需要重新绘制,或者View的onDraw方法处理事情太多。

在Android 6.0中,有更多的颜色被加了进来,如下图所示:

Profile GPU Rendering可以找到渲染有问题的界面,但是想要修复的话,只依赖Profile GPU Rendering是不够的,可以用另一个工具Hierarchy Viewer来查看布局层次和每个View所花的时间,这个工具会在下一篇文章进行介绍。

3.Systrace

Systrace是Android4.1中新增的性能数据采样和分析工具。它可帮助开发者收集Android关键子系统(SurfaceFlinger、WindowManagerService等Framework部分关键模块、服务,View体系系统等)的运行信息。Systrace的功能包括跟踪系统的I/O操作、内核工作队列、CPU负载以及Android各个子系统的运行状况等。对于UI显示性能,比如动画播放不流畅、渲染卡顿等问题提供了分析数据。

使用Systrace

Systrace跟踪的设备要在Android4.1版本以上,对于Android4.3版本之前和4.3版本之后使用上有点区别,现在也很少有人用Android4.3之前的版本,因此这里只讲Android4.3版本的使用方法。Systrace可以在DDMS上使用,可以使用命令行来使用,也可以在代码中进行跟踪。接下来分别来介绍这三种方式。

在DDMS中使用Systrace

1.首先我们要打开Android Studio的Tool中的Android Device Monitor,并连接手机。

2.点击Systrace按钮进入抓取设置界面,如下图所示。

抓取设置界面可以设置跟踪的时间,以及trace文件输出的地址等内容。如下图所示。

3.设置完成后,我们就来操作的跟踪的过程。跟踪时间结束后,生成trace.html文件。

4.用Chrome打开trace.html文件进行分析。分析的方法,后文会讲到。

用命令行使用Systrace

Android 提供一个python脚本文件 systrace.py,它位于Android SDK 目录 /tools/systrace 中,我们可以执行以下命令来使用Systrace:

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

在代码中使用Systrace

Systrace并不会追踪应用的所有工作,在Android4.3及以上版本的代码中,可以使用Trace类对应用中的具体活动进行追踪。

Android源码中也引用了Trace类,比如RecyclerView:

...
 private final Runnable mUpdateChildViewsRunnable = new Runnable() {
        public void run() {
            if (!mFirstLayoutComplete) {
                return;
            }
            if (mDataSetHasChangedAfterLayout) {
                TraceCompat.beginSection(TRACE_ON_DATA_SET_CHANGE_LAYOUT_TAG);
                dispatchLayout();
                TraceCompat.endSection();
            } else if (mAdapterHelper.hasPendingUpdates()) {
                TraceCompat.beginSection(TRACE_HANDLE_ADAPTER_UPDATES_TAG);
                eatRequestLayout();
                mAdapterHelper.preProcess();
                if (!mLayoutRequestEaten) {
                    rebindUpdatedViewHolders();
                }
                resumeRequestLayout(true);
                TraceCompat.endSection();
            }
        }
    };
    ...

TraceCompat类对Trace类进行了封装,只会在Android4.3及以上版本才会使用Trace类,其中beginSection方法和endSection方法之间的代码会被追踪,endSection方法会只会结束最近的beginSection方法,因此要保证beginSection方法和endSection方法的调用次数要相同。

用Chrome分析Systrace

通过前面的方法生成的trace.html需要用Chrome打开,打开后效果如下图所示。

我们可以使用W键和S键进行放大和缩小,A键和D键进行左右移动。

Alert区域

首先来看Alert区域,这一区域会标记处性能有问题的点,单击叹号图标就可以查看某一个Alert的问题描述,如下所示。

这个Alert指出了View在Measure/Layout时耗费了大量的时间,导致出现jank(同一帧画了多次)。给出的建议是避免在动画播放期间控制布局。

CPU区域

接下来我们来查看CPU区域,每一行代表一个CPU核心和它执行任务的时间片,放大后会看到每个色块代表一个执行的进程,色块的长度代表其执行时间,如下图所示。

图中CPU 0主要执行adbb线程和InputReader线程,CPU 2主要执行了surfaceflinger线程和ordinatorlayout进程中的RenderThread线程,我们点击RenderThread色块,会给出RenderThread的相关信息,如下图所示。

图中给出了当前色块所运行的线程和进程、开启时间和持续时间等信息。

应用区域

应用区域会显示应用的帧数,如下图所示。

Systrace会给出应用中的Frames分析,每一帧就是一个F圆圈,F圆圈有三种颜色,其中绿色表示Frame渲染流畅,黄色和红色则代表渲染时间超过了16.6ms,其中红的更严重些。我们点击红色F圆圈,会给出该Frame的信息,如下图所示。

从图中可以看出,Frame给出了问题提示:Scheduling delay(调度延迟),当一帧绘制时间超过19ms会触发该提示,更何况这一帧已经有将近40ms了。导致这一问题产生的原因主要是线程在绘制时,在很长一段时间都没有分配到CPU时间片,因此无法继续进行绘制。按m键来高亮该时间段,我们来查看CPU的情况,如下图所示。

可以看出这个时间段中两个CPU都在满负荷运行。至于具体是什么让CPU繁忙,则需要使用Traceview来进行分析。

Alerts总体分析

点开最右边的Alerts按钮会给出Alert的总体分析,如下图所示。

Alerts会给出Alert类型,以及出现的次数。有了这些总体的分析,方便开发者对该时间段的绘制性能有一个整体的大概了解,便于进行下一步分析。

由于Systrace 是以系统的角度返回一些信息,只能为我们提供一个概览,它的深度是有限的,我们可以用它来进行粗略的检查,以便了解大概的情况,但是如果要分析更详细的,比如要找到是什么让CPU繁忙,某些方法的调用次数等,则还要借助另一个工具:Traceview。

4.Traceview

TraceView是Android SDK中自带的数据采集和分析工具。一般来说,通过TraceView我们可以得到以下两种数据:

- 单次执行耗时的方法。

- 执行次数多的方法。

使用Traceview

要分析Traceview,则首先要得到一个trace文件,trace文件的获取有两种方式,分别是在DDMS中使用和在代码中加入调试语句,下面分别对这两种方式进行介绍。

DDMS中使用

1.首先我们要打开Android Studio的Tool中的Android Device Monitor,并连接手机。

2.选择相应的进程,并单击Start Method Profiling按钮。

3.对应用中需要监控的点进行操作。

4.单击Stop Method Profiling按钮,会自动跳到TraceView视图。

代码中加入调试语句

如果开发中出现不好复现的问题,则需要在代码中添加TraceView监控语句,代码如下所示。

Debug.startMethodTracing();
...
Debug.stopMethodTracing();

在开始监控的地方调用startMethodTracing方法,在需要结束监控的地方调用stopMethodTracing方法。系统会在SD卡中生成trace文件,将trace文件导出并用SDK中的Traceview打开即可。当然不要忘了在manifest中加入 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>权限。

分析Traceview

为了分析Traceview,我们来举一个简单的例子来生成trace文件,这里采用第二种方式:代码中加入调试语句。代码如下所示。

public class CoordinatorLayoutActivity extends AppCompatActivity {
    private ViewPager mViewPager;
    private TabLayout mTabLayout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tab_layout);
        Debug.startMethodTracing("test");//1
        initView();
   ...
    }

    private void initView() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void onStop() {
        super.onStop();
        Debug.stopMethodTracing();
    }
}

在注释1处调用了startMethodTracing方法开始监控,其中test是生成的trace文件的名称。在initView中我们特意调用sleep方法来做耗时操作。在onStop方法中我们调用了stopMethodTracing方法结束监控。这时会在SD卡根目录生成test.trace文件,我们将该文件导出到桌面,用Traceview来分析test.trace文件,我们在cmd中执行如下语句。

我们进入traceview所在的目录(直接将traceview.bat拖入到cmd中),并执行上图的traceview语句后会弹出Traceview视图,它分为两部分,分别是时间片面板和分析面板,我们先来看时间片面板,如下图所示。

其中x轴代表时间的消耗,单位为ms,y轴代表各个线程。一般会查看色块的长度,明显比较长的方法重点去关注,具体的分析还得看分析面板,如下图所示。

每一列数据的代表的含义如下表所示。

列名 含义
Name 该线程运行过程中调用的函数名
Incl Cpu Time% 某个方法包括其内部调用的方法所占用CPU时间百分比
Excl Cpu Time% 某个方法不包括其内部调用的方法所占用CPU时间百分比
Incl Real Time% 某个方法包括其内部调用的方法所占用真实时间百分比
Excl Real Time% 某个方法不包括其内部调用的方法所占用真实时间百分比
Calls + Recur Calls / Total 某个方法次数+递归调用次数
Cpu Time / Call 该方法平均占用CPU时间
Cpu Time / Call 该方法平均占用真实时间
Incl Cpu Time 某个方法包括其内部调用的方法所占用CPU时间
Excl Cpu Time 某个方法不包括其内部调用的方法所占用CPU时间
Incl Real Time 某个方法包括其内部调用的方法所占用真实时间
Excl Real Time 某个方法不包括其内部调用的方法所占用真实时间

因为我们用sleep方法来进行耗时操作,所以这里我们可以单击Incl Real Time来进行降序排列。其中有很多系统调用的方法,我们来进行一一过滤。最终我们发现了CoordinatorLayoutActivity的initView方法Incl Real Time的时间为1000.493ms,这显然有问题,如下图所示。

从图中我们可以看出是调用sleep方法导致的耗时。关于Traceview还有很多种分析情况,就需要大家在平时进行积累了。

好了关于绘制性能分析,就讲到这,如果觉得不过瘾,本系列的后续文章还有大波的内容会持续向你砸来。

参考资料

《Android群英传 神兵利器》

《Android应用性能优化最佳实践》

http://blog.csdn.net/itachi85/article/details/6857324

http://www.cnblogs.com/sunzn/p/3192231.html

http://blog.csdn.net/androiddevelop/article/details/8223805

http://www.tuicool.com/articles/jMfiUjj

http://www.mobile-open.com/2015/85005.html



欢迎关注我的微信公众号,第一时间获得博客更新提醒,以及更多成体系的Android相关原创技术干货。

扫一扫下方二维码或者长按识别二维码,即可关注。

时间: 2024-10-06 20:23:21

Android绘制优化(一)绘制性能分析的相关文章

Android中RelativeLayout和LinearLayout性能分析

先看一些现象吧:用eclipse或者Android studio,新建一个Activity自动生成的布局文件都是RelativeLayout,或许你会认为这是IDE的默认设置问题,其实不然,这是由 android-sdk\tools\templates\activities\BlankActivity\root\res\layout\activity_simple.xml.ftl 这个文件事先就定好了的,也就是说这是Google的选择,而非IDE的选择.那SDK为什么会默认给开发者新建一个默认的

Android开发之Java集合类性能分析

对于Android开发者来说深入了解Java的集合类很有必要主要是从Collection和Map接口衍生出来的,目前主要提供了List.Set和 Map这三大类的集合,今天就他们的子类在标准情况和多线程下的性能做简单的分析. Collection接口主要有两种子类分别为List和Set,区别主要是List保存的对象可以重复,而Set不可以重复,而Map一般为key-value这样的对应关系,比如我们常用的HashMap. 一.List 主要有ArrayList.LinkedList.Vector

unity直连android真机在Profiler性能分析测试

基础步骤: 1.Unity打开你要测试的项目:File–Build Settings 2.如下图,按图顺序进行1.2.3.4.5操作,如果做过了,2就是灰色的,不能被点击,4和5需要相对应. 3.确保手机连接电脑,USB调试已打开,一定要关闭windows防火墙,防火墙会屏蔽大多数端口,影响手机端口连接(这个大坑搞了我好久). 找到你的Android SDK 目录,进入platform-tools,我的是E:\Program Files\android-sdk-windows\platform-

Android卡顿优化:卡顿分析方法

基础知识在具体讲卡顿工具前,你需要了解一些基础知识,它们主要都和 CPU 相关.造成卡顿的原因可能有千百种,不过最终都会反映到CPU 时间上.我们可以把 CPU 时间分为两种:用户时间和系统时间.用户时间就是执行用户态应用程序代码所消耗的时间:系统时间就是执行内核态系统调用所消耗的时间,包括 I/O.锁.中断以及其他系统调用的时间. CPU 性能在开发过程中,我们可以通过下面的方法获得设备的 CPU 信息.// 获取 CPU 核心数cat /sys/devices/system/cpu/poss

【性能分析】初探VS2010中的Profile(性能剖析)功能

VS2010中的Profile(性能剖析)功能十分实用,它可以协助程序员迅速锁定当前程序的性能瓶颈,为程序的优化做准备. 点击VS2010的Analyze菜单,选择Launch Performance Wizard,依照提示可以很方便地完成Profile的必需配置.可能你会碰到"Injection of runtime library failed"错误,这时就不要使用Wizard,而要选择Analyze下拉菜单中的Profiler->Attach/Detach...,将Prof

【转】Android性能优化-过度绘制解决方案

转载请注明出处:http://blog.csdn.net/a740169405/article/details/53896497 过度绘制: 屏幕上某一像素点在一帧中被重复绘制多次,就是过度绘制. 下图中多个卡片跌在一起,但是只有第一个卡片是完全可见的.背后的卡片只有部分可见.但是android系统在绘制时会将下层的卡片进行绘制,接着再将上层的卡片进行绘制.但其实,下层卡片不可见的部分是不需要进行绘制的,只有可见部分才需要进行绘制.  依据过度绘制的层度可以分成: - 无过度绘制(一个像素只被绘

Android绘制优化(二)布局优化

相关文章 Android绘制优化(一)绘制性能分析 前言 我们知道一个界面的测量和绘制是通过递归来完成的,减少布局的层数就会减少测量和绘制的时间,从而性能就会得到提升.当然这只是布局优化的一方面,那么如何来进行布局的分析和优化呢?本篇文章会给你一个满意的答案. 1.布局优化工具 在讲到如何去布局优化前,我们先来学习两种布局优化的工具. Hierarchy Viewer Hierarchy Viewer是Android SDK自带的可视化的调试工具,用来检查布局嵌套和绘制的时间.需要注意的是在在A

android 性能分析、优化

1.主要介绍了一些分析工具,比如GT.ITest等http://www.jianshu.com/p/8b77d394b2a6 2.详细介绍啦android平台常见性能优化工具http://blog.csdn.net/yanbober/article/details/48394201例如:UI方面:android系统提供的GPU OverDraw 过度绘制工具:GPU呈现模式分析等. Lint快速分析不合理懂UI布局:HierarchyViewer 具体分析View布局.内存方面:介绍了Memor

Android 中View的绘制机制源码分析 一

尊重原创: http://blog.csdn.net/yuanzeyao/article/details/46765113 差不多半年没有写博客了,一是因为工作比较忙,二是觉得没有什么内容值得写,三是因为自己越来越懒了吧,不过最近我对Android中View的绘制机制有了一些新的认识,所以想记录下来并分享给大家.在之后的几篇博客中,我会给大家分享如下的内容: 1.View中measure(),layout(),draw()函数执行过程分析,带领大家详细分析View的尺寸测量过程,位置计算,并最终