最近要对新接手的一个Android项目做性能优化,经过大量的查阅学习,总结了一些知识点,特此记录。此篇记录UI性能方面的优化思路。
说起UI的优化,不得不了解一下过度绘制的概念、产生原因和表现、查看以及优化overdraw的方法。
1. 过度绘制(Overdraw)概念
是指在一帧的时间(16.67ms)内,像素被多次绘制
2. 产生的原因和表现
一个像素被绘制一次是最理想的状态,但是实际情况中,由于重叠的布局导致一些像素被多次绘制,每次绘制都是CPU的一组绘图命令和GPU的一些操作,在单次绘制的时长超过16ms时,便会出现掉帧现象,也就是卡顿。
3. 如何查看
Android系统是为我们提供了测量overdraw的功能的,打开步骤:开发者选项=>调试GPU过度绘制(show GPU overdraw),打开之后便可以查看目标页面的overdraw状态了。打开了之后系统提供了四种不同的颜色来绘制屏幕,用来指示overdraw的位置和程度:①没有颜色:没有发生overdraw,像素只被绘制一次。②蓝色:区域像素被绘制两次。如果大片的蓝色是可以接受的,如果整个屏幕都是蓝色,便可以在布局的时候减少一层。③绿色:区域像素被绘制三次,如果出现绿色,虽然可以接受,但是也需要着手优化和减少。④浅红:区域像素被绘制4次,小范围可以接受。⑤暗红:区域像素被绘制5次。当像素被绘制5次及以上,就是错误的,尽快修复。
4. 优化overdraw的方法
优化overdraw的原则是尽量避免重复对不可见元素的绘制和尽量减少布局层级。这个时候merge、ViewStub标签便能派上用场了。
ViewStub
ViewStub:即高效占位符。
应用场景:在前端开发中,经常是需要根据条件动态显示或隐藏某个view或layout,常用的做法是先对目标View或者layout的可见属性设置成View.GONE,就可以简单灵活地控制显示或者隐藏。但是,这样会浪费资源,因为虽然View或者layout可见性是GONE,但是在inflate布局的时候,目标View或layout依然会被inflate,进而创建对象、被实例化、设置属性值。
这个时候,可以使用ViewStub标签。ViewStub是一个轻量级的View,它一个看不见的,不占布局位置,占用资源非常小的控件。使用时为ViewStub指定布局,在页面inflate时,
只有ViewStub会被初始化,然后当ViewStub被设置为可见的时候,或是调用了ViewStub.inflate()的时候,ViewStub所向的布局才会被Inflate和实例化。使用代码示例:
布局文件:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/bt_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="显示ViewStub" />
<Button
android:id="@+id/bt_change"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="更改ViewStub" />
<Button
android:id="@+id/bt_hide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="隐藏ViewStub" />
</LinearLayout>
<!--通过ViewStub的自身id,找到控件并调用 ViewStub#inflate()之后就失效
inflatedId是在ViewStab#inflate()之后替换的View 的id
layout是用来替换ViewStub的布局-->
<ViewStub
android:id="@+id/view_stub_test"
android:inflatedId="@+id/rl_item"
android:layout="@layout/layout_item_list_database_prac"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
activity中使用代码,贴出按钮的点击事件代码:
switch (v.getId()) {
case R.id.bt_show:
/****
* ViewStub 只能调用inflate()一次,
* 调用之后,会被从视图树中移除,所以进行判空
*/
if (findViewById(R.id.view_stub_test) != null)
((ViewStub) findViewById(R.id.view_stub_test)).inflate();
else {
/**
* ViewStub为空就是已经被加载,用ViewStub的inflatedId属性查找替换布局
*/
findViewById(R.id.rl_item).setVisibility(View.VISIBLE);
}
break;
case R.id.bt_change:
if (!findViewById(R.id.rl_item).isShown()) {
return;
}
i = ++i;
((TextView) findViewById(R.id.text_layout_item_data_base_recycler)).setText("change" + (i));
break;
case R.id.bt_hide:
if (findViewById(R.id.rl_item) == null)
return;
findViewById(R.id.rl_item).setVisibility(View.GONE);
break;
}
首次显示页面:
点击 显示ViewStub Button:
点击 更改ViewStub Button:
点击 隐藏ViewStub Button:
至此,ViewStub标签的使用介绍完毕,下面介绍merge标签的使用: