绘制原理

View 的绘制流程有3个步骤,分别是measure 、layout 和draw ,它们主要运行在系统的应用框架层,而真正将数据渲染到屏幕上的则是系统Native层的SurfaceFlinger服务来完成的。

绘制过程主要由CPU来进行Measure 、Layout 、Record 、Execute的数据计算工作, GPU负责栅格化、渲染。CPU 和GPU 是通过图形驱动层来进行连接的,图形驱动层维护了一个队列, CPU 将display list 添加到该队列中,这样GPU 就可以从这个队列中取出数据进行绘制。由于人的大脑在画面是如果60fps 则不会感觉到卡顿,如果低于60fps ,比如50fps 则会感觉到卡顿。这是因为人类的大脑会不断接收井处理眼球看到的信息,单位时间内越多的帧被处理,越能有效地被大脑识别,大脑能感知的最小帧数在10fps ~12fps ,这个时候大脑就分不清这个图像是静止的还是变化的。在Android系统中是以每秒60帧为满帧的,那么只要将1秒÷60帧,就能得出每帧为16毫秒(ms)时为满帧的界限,每帧快于16ms即为流畅。

Android系统每隔16ms 发出VSYNC信号,触发对UI进行渲染,如果每次渲染都成
功,这样就能够达到流畅的画面所需要的60fps ,那什么是VSYNC 呢? VSYNC 是Vertical Synchronization ( 垂直同步)的缩写,是一种定时中断, 一旦收到VSYNC 信号,CPU就开始处理各帧数据。如果某个操作要花费24ms ,这样系统在得到VSYNC信号时无法进行正常的渲染,会发生丢帧。用户会在32ms 中看到同一帧的画面。(之所以是32ms内看到是同一帧,是因为,第一个VSYNC信号来的时候,才进行UI渲染,但是在下一个VSYNC信号来之前,还未渲染完成,这样,会接着渲染这帧,假设剩下的帧8ms就能渲染完,但是,由于需要等到第三个个VSYNC信号,才能再次触发UI渲染,在等待第三个VSYNC信号来时,界面还未更新,所以在两个VSYNC信号的时间内,也就是32ms时间内都看到的时候同一帧画面)。

造成app卡顿的原因很多:
• 布局Layout过于复杂,无法在16ms内完成渲染。
• 同一时间动画执行的次数过多,导致CPU或GPU负载过重。
• View过度绘制,导致某些像素在同一帧时间内被绘制多次。
• 在UI线程中做了稍微耗时的操作。
• GC回收时暂停时间过长或者频繁的GC产生大量的暂停时间。

Profile GPU Rendering

下面介绍一个分析页面渲染的工具,Profile GPU Rendering。
通过打开手机的开发者选项,接着打开Profile GPU Rendering,在中文安卓系统下译为“GPU显示配置文件”或“GPU呈现模式分析”等,根据不同厂商定制系统叫法稍有不同通过开启Profile GPU Rendering,可以发现渲染有问题的页面。打开后屏幕下方的柱状图每一根代表一帧,其高度表示“渲染这一帧耗时”,随着手机屏幕界面的变化,柱状图会持续刷新每帧用时的具体情况(通过高度表示)。而这根绿线所标示的高度即为16ms线,低于绿线即为流畅。

通过开启Profile GPU Rendering,可以发现渲染有问题的页面,但是想要修复的话,只依赖Profile GPU Rendering,是不够的,需要使用Hierarchy Viewer 来查看布局层次和每个View所花的时间。

android 4.1系统提供了Profile GPU Rendering功能的显示的彩色柱状图,只有三红颜色,分别是:橙色,红色,蓝色。

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

从6.0开始,将每一帧的渲染过程拆分成了8个步骤,每个步骤一种颜色,每种步骤的意义如下:

  • Swap Buffers
    交换缓冲区,表示处理时间,和上面的橙色一样。

  • Command Issue
    表示执行时间,和上面的红色一样。

  • Sync & Upload
    表示的是准备当前界面上有待绘制的图片所耗费的时间,为了减少该段区域的执行时间,我们可以减少屏幕上的图片数量或者是缩小图片的大小

  • Draw
    表示测量和绘制视图列表所需要的时间,蓝色线条越高表示每一帧需要更新很多视图,或者View的onDraw方法中做了耗时操作,和上面的蓝色一样

  • Measure/Layout
    表示布局的onMeasure与onLayout所花费的时间,一旦时间过长,就需要仔细检查自己的布局是不是存在严重的性能问题

  • Animation
    表示计算执行动画所需要花费的时间,包含的动画有ObjectAnimator,ViewPropertyAnimator,Transition等等。一旦这里的执行时间过长,就需要检查是不是使用了非官方的动画工具或者是检查动画执行的过程中是不是触发了读写操作等等

  • Input Handling
    表示系统处理输入事件所耗费的时间,粗略等于对事件处理方法所执行的时间。一旦执行时间过长,意味着在处理用户的输入事件的地方执行了复杂的操作

  • Misc Time/Vsync Delay
    表示在主线程执行了太多的任务,导致UI渲染跟不上vSync的信号而出现掉帧的情况。
    Profile GPU Rendering工具只是一种直观的体现页面每帧渲染的过程。但是想要获取到每帧的具体渲染的数据,就需要使用Systrace工具。

Systrace

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

下面只讲解4.3以后如何使用(4.3以前的版本已经很少人使用了):
方式一:在Android Device Monitor中使用Systrace,(AS 3.X中启动Android Device Monitor,要在sdk目录下,找打tools目录,在tools目录下,双击monitor.bat,即可启动Android Device Monitor。)在打开的Android Device Monitor面板上点击Systrace按钮,点击确定,就可以启动Systrace工具进行跟踪了。也可以在打开的面板中,设置输出的trace.html文件的位置,以及跟踪的时间等参数。

点击上图红框中的按钮,就会弹出下图:

上图中红框中的各项都可以进行设置,都对应着相应的命令。

方式二:使用命令行,进入到Android的sdk\platform-tools\systrace目录下,使用Python脚本,在命令行中输入如下命令

python systrace.py --time=10 -o newtrace.html sched gfx  view vm

命令行的格式:

python systrace.py [options] [category1] [category2] ... [categoryN]

其中options可取值中比较重要的几个参数如下:

-a <package_name>:这个选项可以开启指定包名App中自定义Trace Label的Trace功能。也就是说,如果你在代码中使用了Trace.beginSection("tag"), Trace.endSection;默认情况下,你的这些代码是不会生效的,因此,这个选项一定要开启!

-t N:用来指定Trace运行的时间,取决于你需要分析过程的时间;还是那句话,在需要的时候尽可能缩小时间;当然,绝对不要把时间设的太短导致你操作没完Trace就跑完了,这样会出现Did not finish 的标签,分析数据就基本无效了。

-l:这个用来列出你分析的那个手机系统支持的Trace模块;也就是上面命令中 [category1]能使用的部分;不同版本的系统能支持的模块是不同的,一般来说,高版本的支持的模块更多。

-o FILE:指定trace数据文件的输出路径,如果不指定就是当前目录的trace.html

systrace.py -l 可以输出手机能支持的Trace模块,而且输出还给出了此模块的用途;常用的模块如下:

sched: CPU调度的信息,非常重要;你能看到CPU在每个时间段在运行什么线程;线程调度情况,比如锁信息。
gfx:Graphic系统的相关信息,包括SerfaceFlinger,VSYNC消息,Texture,RenderThread等;分析卡顿非常依赖这个。
view: View绘制系统的相关信息,比如onMeasure,onLayout等;对分析卡顿比较有帮助。
am:ActivityManager调用的相关信息;用来分析Activity的启动过程比较有效。
dalvik: 虚拟机相关信息,比如GC停顿等。
binder_driver: Binder驱动的相关信息,如果你怀疑是Binder IPC的问题,不妨打开这个。
core_services: SystemServer中系统核心Service的相关信息,分析特定问题用。

这些命令行对应图形界面的很多配置选项,对于不想记住这么多命令的同学,可以使用图形界面的方式生成Systrace报告。

由于systrace是在系统级显示有关进程的信息,因此很难在HTML报告中的某个特定时间知道您的应用程序正在执行什么方法。如果想精确的定位到处问题的地方,就需要在代码中使用Systrace。在Android 4.3以上的版本中,才能使用Trace类对应用进行具体活动的跟踪。

Trace.beginSection("SysTraceActivity");//方法中存入一个tag值,可以任意取,不过最好取自己方便识别的tag
...(需要跟踪的代码)
Trace.endSection();

注意:这两个方法最好是成对的出现,两个方法都只能运行在同一个线程中。

在代码中示例如下:

public class SysTraceActivity extends AppCompatActivity {@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);Trace.beginSection("SysTraceActivity");try {Thread.sleep(3800);setContentView(R.layout.activity_systrace);} catch (InterruptedException e) {e.printStackTrace();}finally {Trace.endSection();}}
}

在代码中加了自定义的label后,依然需要按照方式一或者方式二来抓取Systrace报告。如果是使用方式一生成Systrace报告,需要在Enable Application Traces from:后面的下拉选择框中,指定要跟踪的进程, 如果是使用命名行的方式,则需要在-a <package_name>,这样在代码中添加的自定义label才会生效。 完成Systrace报告的抓取后会生成一个html文件,需要中chrome浏览器打开,打开后的,下图是生成的Systrace 报告

上图中,红色的区域,从上到下,分别是搜索区,Alerts区域,Kernel区,进程区。
生产的html文件通过chrome解析出来,由于信息很多,展示的图形会很小, 查看时,可以使用以下快捷键
'w’按键:放大
's’按键:缩小
'd’按键:向右平移
'a’按键:向左平移

  • 搜索区
    可以在里面输入自己感兴趣的关键字来进行搜索
  • Alerts区域
    是专门用来显示高亮的性能问题的展示区域,这部分是我们分析这个报告需要的重点分析的部分
  • Kernel区
    展示cpu的个数,以及各个cpu分配给各个进程的线程的时间,可以通过点击键盘的w键对html页面进行方法显示,这样就可以查看清楚,每个颜色部分的长度代表cpu分配给这个进程线程的时间,不同的颜色代表了不同的线程,点击每个颜色块,就会看到如下的信息:

    图中显示了色块是在SurfaceFlinger进程,进程id是3718,线程是 Binder_4线程等信息。
  • 进程区
    进程区列出了很多的进程,我们需要找出自己的app的进程,查看相关的信息,

    上图中就是我们自身的app的进程相关的信息。其中,重点观察UI Thread 和 Render Thread这两个线程,这两个线程负责UI的渲染的相关工作。重上图中,可以看到,右侧有几个红色的F圆圈,以及很多的绿色的F圆圈。每一个F圆圈代表了一帧,红色和黄色的F圆圈,表示渲染一帧的时间超过了16ms,这些圆圈是需要重点分析的部分。
    点击其中一个红色的F圆圈:

Systrac报告只能分析出大概的位置,但是如果要分析更详细的,比如要找到是什么让CPU繁忙,某些方法的调用次数等,则还要借助另一个工具:Traceview。
关于浏览 Systrace 报告,可以查看官网:https://developer.android.google.cn/studio/profile/systrace/navigate-report

TraceView

TraceView 是Android 平台特有的数据采集和分析工具。它本身是一个数据分析工具,而数据的采集则需要使用Android SDK中的Debug类或者Android Device Monitor工具。

二者的用法如下:

  • 借助 Android SDK 中的 Android Device Monitor 工具。Android Device Monitor可采集系统中某个正在运行的进程的函数调用信息。
    对开发者而言,此方法适用于没有目标应用源代码的情况。
    具体操作如下:
    打开Android Device Monitor,对于AS 3.X中启动Android Device Monitor,要在sdk目录下,找打tools目录,在tools目录下,双击monitor.bat,即可启动Android Device Monitor。启动后如下图所示:

    预先准备好要收集的信息页面,当点击上图中的 Start Method Profiling 按钮,如果这个按钮是灰色不能点击,需要先在侧边栏选中要收集的应用。点击 Start Method Profiling 按钮后会弹出一个对话框如下所示:

    点击对话框中的确认按钮后,就开始了信息的收集,这时就到相应的卡顿页面去操作,操作完成后,点击
    Stop Method Profiling 按钮,当数据收集完成后,就会自动的打开收集的trace文件。如下图:

    图中分为上下两个区域,分别是Timeline Panel(时间线面板区域)和 Profile Panel(分析面板区域)。上图中的上半部分为 Timeline Panel(时间线面板)中左边 Pane 显示的是测试数据中所采集的线程信息,右边的pane显示的是时间线,时间线上是每个线程测试时间段内所涉及的函数调用信息。这些信息包括函数名、函数执行时间等。
    分析面板中绿色框中的信息代表的意义如下所示:

列名                                                                              含义
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                                   某个方法不包括其内部调用的方法所占用真实时间

  • 在一些关键代码段开始前调用 Android SDK 中 Debug 类的 startMethodTracing 函数,并在关键代码段结束前调用 stopMethodTracing 函数。这两个函数运行过程中将采集运行时间,内该应用所有线程(注意,只能是 Java 线程)的函数执行情况,并将采集数据保存到 /mnt/sdcard/ 下的一个文件中。然后需要利用 SDK 中的 TraceView 工具来分析这些数据。下面演示这种方式收集trace文件,并分析该文件。
public class TraceActivity extends AppCompatActivity {@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_trace);Debug.startMethodTracing("test");initView();}private void initView(){try {Thread.sleep(3800);} catch (InterruptedException e) {e.printStackTrace();}}@Overrideprotected void onStop() {super.onStop();Debug.stopMethodTracing();}
}

当启动了这个TraceActivity类后,调用完成OnCreate方法后,这时会在SD卡根目录生成test.trace文件,我们将该文件导出到桌面,用Android Device Monitor来分析test.trace文件。
在Android Device Monitor页面,点击File -->Open File,选择生成的test.trace文件,即可打开这个test.trace文件,如下图所示:

打开后,可以看到下面的分析面板中有很多的方法,为了快速的定位到我们自己的app的方法,可以在底部的Find栏中输入我们自己的app的包名,这样就可以快速的定位到了。通过点击我们自己app的方法,可以发现TraceActivity的initView方法耗时很长,这个时长是3801.247ms,在向下看,发现initView方法内部是调用了java.lang.Thread.sleep()方法,这个方法的耗时3801.253ms,这样就可以发现是由于Thread.sleep()方法导致的耗时。这里只是举了一个小的例子进行了演示,更多的分析技巧,需要大家平时多积累。

布局优化

上面介绍的是app中出现了卡顿的问题,如何定位问题,并解决,下面介绍,如何在项目开发中写出减少页面卡顿,提高性能的布局。在此之前,要先介绍两个工具,第一个是Layout Inspector工具,这个工具是来替代Hierarchy Viewer的,hierarchyviewer 已经被废弃了(Android SDK Tools Revision 25.3.0 (Feb 2017))
既然AS 不提供 DDMS面板了那肯定有替代的工具啊,经过查找总结如下:DDMS 和 Systrace、Hierarchy Viewer都不用了。使用Android Profiler替代DDMS和Systrace,Layout Inspector 替代Hierarchy Viewer。Android Studio 升级3.x 后 Android Monitor / DDMS 面板没有了。要想使用Layout Inspector工具,需要在AS的工具栏中点击Tools
选项,可以看到Layout Inspector

点击Layout Inspector,就会弹出如下图的对话框:

选中要查看布局的进程,这时,不要立刻点击对话框的ok按钮,先操作手机上的app,进入到要查看的布局的
页面,在点击ok按钮,这样就会在captures文件夹下生成 包名_日期.li的文件,例如:
test.cn.example.com.androidskill_2019.11.05_22.04.li,可以打开这个文件,
就可以看到如下图;

图中,分了三个模块,
第一个模块是ViewTree,这个模块中显示了我们要查看的布局页面的View是树形层次结构。
第二个模块是Load Overlay,这个模块是预览当前要分析的布局的页面
第三个模块是Properties Table,这个模块从名字上看,就知道是显示页面的各种属性的。

这就是Layout Inspector工具查看布局的使用步骤。如果设备上的布局发生变化,布局检查器不会更新。 您必须再次点击 Tools > Android > Layout Inspector,创建一个新的快照。每一个快照都将保存到 project-name/captures/ 内一个单独的 .li 文件中。相比于Hierarchy Viewer工具,它的优点是,可以针对真机调试,但是界面不如Hierarchy Viewer 直观。

Layout Inspector工具官方文档

下面继续介绍第二个工具Lint,打开这个工具的方式有如下几种:
方式一:右键 module、目录或者文件,选择 Analyze -> Inspect Code,打开 Lint 代码检查结果窗口
方式二:在AS的工具栏,选择Analyze选项,点击其中的Inspect Code,也可以打开Lint代码的检查结果窗口
两种方式打开的界面如下图:

在上图中,可以调整Lint检查的范围。选择好范围后,点击ok按钮,这样AS就开始进行静态代码检测了。过几分中,就会呈现检查结果:

从Lint检查结果可以看出,对Android方面的检查,主要分以下6点:
1.Accessibility,也就是可达性
2.Correctness,正确性
3.Internationalization,国际化
4.Performance,性能
5.Security,安全性
6.Usability,可见性
点击每一个小的检查项中的列出的问题,可以看到相关的描述信息,可以根据这些描述信息进行修改,优先解决error级别的问题。由于分析出来是问题太多,这里就不一一举例分析检查出来的每一个问题了。从上图中,可以看到,Lint不仅检查了android的问题,还检查了Spelling(拼写),XML(xml)文件的一些问题等,可以说Lint工具还是很强大的。

如果想自定义Lint的检查提示,可以通过File——>Settigns——>Editor——>Inspections,
会弹出如下界面:

选中上图红框中的任意一项, 比如Android,这时,会出现如下所示的,更改Lint检查提示的级别的下拉选:

在右侧,会出现Severity的下拉选,可以点击红框中的下拉选,进行更改Lint的检查提示级别。

具体的布局优化方式

  • 合理的使用布局
    如果在一个页面中,如果可以使用RelativeLayout来LinearLayout,如果是用LinearLayout使得层级嵌套了多层,则建议使用RelativeLayout,这样就可以减少view的层架嵌套和减少view的个数。如果页面很复制,推荐使用ConstraintLayout布局。

  • 使用Include标签来进行布局复用
    当include两个相同的布局时,如果区别?可以在include时指定一个新的id,用来区别。相当于将原来的指定的id冲掉,又指定了新的id。

<?xml version="1.0" encoding="utf-8"?>
<test.cn.example.com.androidskill.ui.compact.QQSlidingMenu xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="wrap_content"android:layout_height="match_parent"><LinearLayoutandroid:layout_width="wrap_content"android:layout_height="match_parent"android:orientation="horizontal"><include layout="@layout/qq_menu"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/splash12"></LinearLayout></LinearLayout>
</test.cn.example.com.androidskill.ui.compact.QQSlidingMenu>

qq_menu.xml文件如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><LinearLayoutandroid:layout_width="100dp"android:layout_height="100dp"android:layout_margin="@dimen/dp16"android:gravity="center_vertical"><ImageViewandroid:layout_width="30dp"android:layout_height="30dp"android:src="@drawable/p1"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="@dimen/dp16"android:layout_gravity="center_vertical"android:textSize="18sp"android:text="拍照"/></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="100dp"android:layout_margin="@dimen/dp16"android:gravity="center_vertical"><ImageViewandroid:layout_width="30dp"android:layout_height="30dp"android:src="@drawable/p2"/><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginLeft="@dimen/dp16"android:layout_gravity="center_vertical"android:textSize="18sp"android:text="空间"/></LinearLayout></LinearLayout>
  • 用Merge标签去除多余的层级
    Merge 意味着合井,在合适的场景使用Merge 标签可以减少多余的层级。Merge标签一般和Include 标签搭配使用。上面的示例中,可以将qq_menu.xml文件中的根布局LinearLayout替换成merge,此前的根布局LinearLayout 没有了,但是这里用merge 标签来替代LinearLayout 会导致LinearLayout 失效,布局就会错乱。merge 标签最好是替代FrameLayout 或者布局方向一致的LinearLayout ,比如当前父布局LinearLayout 的布局方向是垂直的,包含的子布局Linear Layout 的布局方向也是垂直的,则可以用merge 标签,而本:J:m景TitleBar 的根布局
    Linear Layout 的布局方向是水平的,显然并不符合这一要求。但是如果执意想要在本场景中使用merge 标签也是可以的,就是用继承自LinearLayout 的自定义View来解决。

  • 使用ViewStub 来提高加载速度
    一个很常见的开发场景就是我们想要一个布局时,并不是所有的控件都需要显示出来,而是显示出一部分,对于这种情况,我们一般采用的方法就是使用View 的GONE 和INVISIBLE 属性,这种方法效率不高,虽然达到了隐藏的目的,但是仍在布局当中,系统仍然会解析它们,可以用ViewStub 来解决这一问题。ViewStub 是轻量级的View ,不可见并且不占布局位置。当ViewStub i周用inflate 方陆或者设置可见时,系统会加载ViewStub
    指定的布局,然后将这个布局添加到ViewStub 中,在对ViewStub 调用inflate 方能或者设置可见之前,它是不占布局空间和系统资源的,它主要的目的就是为目标视图占用一个位置。因此,使用ViewStub 可以提高界面初始化的性能,从而提高界面的加载速度。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><ViewStubandroid:id="@+id/viewstub"android:layout="@layout/qq_menu"android:layout_width="match_parent"android:layout_height="match_parent" /><FrameLayoutandroid:id="@+id/frame"android:layout_width="match_parent"android:layout_height="match_parent" /></RelativeLayout>

在ViewStub标签只使用android:alyout引用了此前写好的布局qq_menu.xml文件,这时,程序运行时,ViewStub 标签所引用的布局是显示不出来的, 因为该布局还没有加载到ViewStub 中,接下来在代码中使用Viewstub

public class SplashActivityOptimize extends FragmentActivity {private Handler mHandler = new Handler();private ViewStub viewStub;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_splash_optimize_layout);viewStub = findViewById(R.id.viewstub);//当窗体加载完毕后,加载SplashActivityOptimize的真正要展示的布局Window window = getWindow();LogUtil.i(window+"");window.getDecorView().post(new Runnable() {@Overridepublic void run() {LogUtil.i(Thread.currentThread().getName());mHandler.post(new Runnable() {@Overridepublic void run() {//将viewstub加载进来viewStub.inflate();}});}});}}

在使用ViewStub 时需要主要以下问题:

  • ViewStub 不能嵌套Merge 标签。
  • ViewStub 只能加载一次,加载后ViewStub 对象会被置为空,这样在ViewStub引用的布局被加载后,就不能用ViewStub 来控制引用的布局了。因此,如果一个控件需要不断地显示和隐藏, 还是要使用View 的Visibility 属性。
  • ViewStu b 操作的是布局文件,如果只是想操作具体的View ,还是要使用View 的Vi sibility 属性。

避免GPU过渡绘制
过度绘制是指在屏幕上某个像素在同一||峡的时间内被绘制多次,从而浪费了GPU 和CPU 的资源。产生这一情况主要有两个原因:
a.在XML 布局中,控件有重叠且都有设置背景。
b.View 的OnDraw 在同一区域绘制多次。
过度绘制是很难避免的,但是过多的过度绘制会·浪费很多资橱,并且导致性能问题,因此,避免过度绘制是十分必要的。我们可以用Android 系统中自带的工具来检测过度绘制。首先要保证系统版本在An droid 4.1 以上,接着在开发者选项中打开调试GPU 过度绘制选项就可以进入GPU 过度绘制模式,如下图所示:

这时屏幕会出现出各种颜色,主要有以下几种。
a.白色:没有过度绘制一一每个像素在屏幕上绘制了一次。
b·蓝色: 一次过度绘制一一每个像素点在屏幕上绘制了两次。
c.绿色:两次过度绘制一一每个像素点在屏幕上绘制了三次。
d.粉色: 三次过度绘制一一每个像素点在屏幕上绘制了四次。
e·红色:四次或四次以上过度绘制一一每个像素点在屏幕上绘制了五次或者五次以上。

合格的页面绘制是以白色和蓝色为主的,绿色以上区域不能超过整体的三分之一,颜色越战越好。
避免过度绘制主要有以下两个方案:
1·移除不需要的background 。
2·在自定义View 的OnDraw 方法中,用canvas.clipRect 来指定绘制的区域,防止重叠的组件发生过度绘制。

Android 绘制优化相关推荐

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

    相关文章 Android绘制优化(一)绘制性能分析 前言 我们知道一个界面的测量和绘制是通过递归来完成的,减少布局的层数就会减少测量和绘制的时间,从而性能就会得到提升.当然这只是布局优化的一方面,那么 ...

  2. Android 绘制优化总结1

    Android性能优化分为很多种,比较常用的有绘制优化.内存优化.耗电优化和稳定性优化等,这个系列我们就来学习性能优化中的绘制优化. 1.绘制原理 Android绘制View有三个主要的步骤,分别是m ...

  3. Android 界面介绍与绘制优化

    Andorid用户界面框架 Android的用户界面框架(Android UI Framework)采用MVC(Model-View-Controller)模型,为用户界面提供了处理用户输入的控制器( ...

  4. Android性能优化典范笔记(1)-GPU绘制性能优化

    Android性能优化典范笔记(1)-GPU绘制性能优化 你还可以再Github上找到我的这篇文章:https://github.com/onlynight/ReadmeDemo/tree/maste ...

  5. 【Android 内存优化】自定义组件长图组件 ( 获取图像宽高 | 计算解码区域 | 设置图像解码属性 复用 像素格式 | 图像绘制 )

    文章目录 一.获取图像真实宽高 二.计算解码区域 三.设置解码参数 内存复用 像素格式 四.图像绘制 五.执行效果 六.源码及资源下载 官方文档 API : BitmapRegionDecoder 在 ...

  6. 【Android 性能优化】布局渲染优化 ( CPU 渲染优化 | 减少布局的嵌套 | 测量布局绘制时间 | OnFrameMetricsAvailableListener | 布局渲染优化总结 )

    文章目录 一. 减少布局嵌套 二. 布局渲染时间测量 1. FrameMetrics 使用流程 2. FrameMetrics 参数解析 3. FrameMetrics 代码示例 三. 布局渲染优化总 ...

  7. 【Android 性能优化】布局渲染优化 ( GPU 过度绘制优化总结 | CPU 渲染过程 | Layout Inspector 工具 | View Tree 分析 | 布局组件层级分析 )

    文章目录 一. GPU 过度绘制优化总结 二. CPU 渲染过程 三. CPU 渲染性能调试工具 Layout Inspector 四. Layout Inspector 组件树 DecorView ...

  8. 【Android 性能优化】布局渲染优化 ( 过渡绘制 | 背景设置产生的过度绘制 | Android 系统的渲染优化 | 自定义布局渲染优化 )

    文章目录 一. 背景设置产生的过度绘制 二. Android 系统的渲染优化 1. 透明组件数据传递 2. GPU 存储机制 3. Android 7.0 之后的优化机制 三. 自定义布局渲染优化 一 ...

  9. Android系统性能优化(68)---绘制优化

    Android性能优化: 绘制优化 前言 在 Android开发中,性能优化策略十分重要 本文主要讲解性能优化中的绘制优化,希望你们会喜欢. 目录 1. 影响的性能 绘制性能的好坏 主要影响 :And ...

最新文章

  1. python哪些模块用于数据分析_python数据解析模块之glom模块的使用(一)
  2. 127. Word Ladder 单词接龙
  3. 腾讯与中国人民大学开源最新研究成果:3TS腾讯事务处理技术验证系统
  4. amd插帧技术如何开启_联想ThinkPad笔记本电脑如何开启CPU的虚拟化技术图文教程...
  5. x11转发:通过ssh远程使用GUI程序
  6. Postman Forbidden (CSRF token missing or incorrect.)
  7. 提前还贷的python计算程序
  8. 第1章 Ext JS快速入门示例[4/4]
  9. 如何用Baas快速在腾讯云上开发小程序-系列3 :实现腾讯云COS API调用
  10. [转载] numpy.inf
  11. SpringCloud集成分布式事务LCN (一)
  12. html实现视频录制,保存和回放
  13. 机器学习中的各种损失函数(Hinge loss,交叉熵,softmax)
  14. YOLOV5训练数据集过程中特殊问题记录
  15. [bat] cmd命令进入用户登录界面和屏幕保护程序
  16. QPixmap的尺寸设置
  17. MCPcounter安装
  18. wireshark常用过滤条件
  19. 3星|《不会讲故事,怎么带团队》:讲好故事的套路
  20. java助教面试自我介绍_助教面试自我介绍参考

热门文章

  1. 【已解决】surface 电池不好充电显示“未连接”,将充电的接口换个方向就解决了
  2. 创建微服务架构的步骤_如何快速搭建一个微服务架构?
  3. SpringBoot Mybatis 读写分离配置
  4. FCAA答题练习收集记录
  5. rounding mode
  6. Android开发:登录/注册界面的编写
  7. pat甲级考试报名费_2019吉林省公务员考试笔面心得
  8. git clone加速(实测推荐)
  9. php中的数据库操作和字符串操作session与cookie操作,php中的数据库操作和字符串操作session与cookie操作...
  10. 对于软件,我是认真的