(转载)性能优化之布局优化

来源:http://www.trinea.cn/android/layout-performance/

本文为Android性能优化的第二篇——布局优化,主要介绍使用抽象布局标签(include, viewstub, merge)、去除不必要的嵌套和View节点、减少不必要的infalte及其他Layout方面可调优点,顺带提及布局调优相关工具(hierarchy viewer和lint)

性能优化专题已完成五部分:

性能优化总纲——性能问题及性能调优方式
性能优化第三篇——Java(Android)代码优化
性能优化第二篇——布局优化
性能优化第一篇——数据库性能优化

性能优化实例

1、抽象布局标签

(1) <include>标签
include标签常用于将布局中的公共部分提取出来供其他layout共用,以实现布局模块化,这在布局编写方便提供了大大的便利。
下面以在一个布局main.xml中用include引入另一个布局foot.xml为例。main.mxl代码如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent" >
 5
 6     <ListView
 7         android:id="@+id/simple_list_view"
 8         android:layout_width="match_parent"
 9         android:layout_height="match_parent"
10         android:layout_marginBottom="@dimen/dp_80" />
11
12     <include layout="@layout/foot.xml" />
13
14 </RelativeLayout>

其中include引入的foot.xml为公用的页面底部,代码如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent" >
 5
 6     <Button
 7         android:id="@+id/button"
 8         android:layout_width="match_parent"
 9         android:layout_height="@dimen/dp_40"
10         android:layout_above="@+id/text"/>
11
12     <TextView
13         android:id="@+id/text"
14         android:layout_width="match_parent"
15         android:layout_height="@dimen/dp_40"
16         android:layout_alignParentBottom="true"
17         android:text="@string/app_name" />
18
19 </RelativeLayout>

<include>标签唯一需要的属性是layout属性,指定需要包含的布局文件。可以定义android:id和android:layout_*属性来覆盖被引入布局根节点的对应属性值。注意重新定义android:id后,子布局的顶结点i就变化了。

(2) <viewstub>标签
viewstub标签同include标签一样可以用来引入一个外部布局,不同的是,viewstub引入的布局默认不会扩张,即既不会占用显示也不会占用位置,从而在解析layout时节省cpu和内存。
viewstub常用来引入那些默认不会显示,只在特殊情况下显示的布局,如进度布局、网络失败显示的刷新布局、信息出错出现的提示布局等。
下面以在一个布局main.xml中加入网络错误时的提示页面network_error.xml为例。main.mxl代码如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent" >
 5
 6     ……
 7     <ViewStub
 8         android:id="@+id/network_error_layout"
 9         android:layout_width="match_parent"
10         android:layout_height="match_parent"
11         android:layout="@layout/network_error" />
12
13 </RelativeLayout>

其中network_error.xml为只有在网络错误时才需要显示的布局,默认不会被解析,示例代码如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent" >
 5
 6     <Button
 7         android:id="@+id/network_setting"
 8         android:layout_width="@dimen/dp_160"
 9         android:layout_height="wrap_content"
10         android:layout_centerHorizontal="true"
11         android:text="@string/network_setting" />
12
13     <Button
14         android:id="@+id/network_refresh"
15         android:layout_width="@dimen/dp_160"
16         android:layout_height="wrap_content"
17         android:layout_below="@+id/network_setting"
18         android:layout_centerHorizontal="true"
19         android:layout_marginTop="@dimen/dp_10"
20         android:text="@string/network_refresh" />
21
22 </RelativeLayout>

在java中通过(ViewStub)findViewById(id)找到ViewStub,通过stub.inflate()展开ViewStub,然后得到子View,如下:

 1 private View networkErrorView;
 2
 3 private void showNetError() {
 4     // not repeated infalte
 5     if (networkErrorView != null) {
 6         networkErrorView.setVisibility(View.VISIBLE);
 7         return;
 8     }
 9
10     ViewStub stub = (ViewStub)findViewById(R.id.network_error_layout);
11     networkErrorView = stub.inflate();
12     Button networkSetting = (Button)networkErrorView.findViewById(R.id.network_setting);
13     Button refresh = (Button)findViewById(R.id.network_refresh);
14 }
15
16 private void showNormal() {
17     if (networkErrorView != null) {
18         networkErrorView.setVisibility(View.GONE);
19     }
20 }

在上面showNetError()中展开了ViewStub,同时我们对networkErrorView进行了保存,这样下次不用继续inflate。这就是后面第三部分提到的减少不必要的infalte。

viewstub标签大部分属性同include标签类似。

上面展开ViewStub部分代码

1 ViewStub stub = (ViewStub)findViewById(R.id.network_error_layout);
2 networkErrorView = stub.inflate();

也可以写成下面的形式

1 View viewStub = findViewById(R.id.network_error_layout);
2 viewStub.setVisibility(View.VISIBLE);   // ViewStub被展开后的布局所替换
3 networkErrorView =  findViewById(R.id.network_error_layout); // 获取展开后的布局

效果一致,只是不用显示的转换为ViewStub。通过viewstub的原理我们可以知道将一个view设置为GONE不会被解析,从而提高layout解析速度,而VISIBLE和INVISIBLE这两个可见性属性会被正常解析。

(3) <merge>标签
在使用了include后可能导致布局嵌套过多,多余不必要的layout节点,从而导致解析变慢,不必要的节点和嵌套可通过hierarchy viewer(下面布局调优工具中有具体介绍)或设置->开发者选项->显示布局边界查看。

merge标签可用于两种典型情况:
a.  布局顶结点是FrameLayout且不需要设置background或padding等属性,可以用merge代替,因为Activity内容试图的parent view就是个FrameLayout,所以可以用merge消除只剩一个。
b.  某布局作为子布局被其他布局include时,使用merge当作该布局的顶节点,这样在被引入时顶结点会自动被忽略,而将其子节点全部合并到主布局中。

以(1) <include>标签的示例为例,用hierarchy viewer查看main.xml布局如下图:


可以发现多了一层没必要的RelativeLayout,将foot.xml中RelativeLayout改为merge,如下:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <merge xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="match_parent"
 4     android:layout_height="match_parent" >
 5
 6     <Button
 7         android:id="@+id/button"
 8         android:layout_width="match_parent"
 9         android:layout_height="@dimen/dp_40"
10         android:layout_above="@+id/text"/>
11
12     <TextView
13         android:id="@+id/text"
14         android:layout_width="match_parent"
15         android:layout_height="@dimen/dp_40"
16         android:layout_alignParentBottom="true"
17         android:text="@string/app_name" />
18
19 </merge>

运行后再次用hierarchy viewer查看main.xml布局如下图:

这样就不会有多余的RelativeLayout节点了。

2、去除不必要的嵌套和View节点
(1) 首次不需要使用的节点设置为GONE或使用viewstub
(2) 使用RelativeLayout代替LinearLayout
大约在Android4.0之前,新建工程的默认main.xml中顶节点是LinearLayout,而在之后已经改为RelativeLayout,因为RelativeLayout性能更优,且可以简单实现LinearLayout嵌套才能实现的布局。
4.0及以上Android版本可通过设置->开发者选项->显示布局边界打开页面布局显示,看看是否有不必要的节点和嵌套。4.0以下版本可通过hierarchy viewer查看。

3、减少不必要的infalte
(1) 对于inflate的布局可以直接缓存,用全部变量代替局部变量,避免下次需再次inflate
如上面ViewStub示例中的

1 if (networkErrorView != null) {
2     networkErrorView.setVisibility(View.VISIBLE);
3     return;
4 }

(2) ListView提供了item缓存,adapter getView的标准写法,如下:

 1 @Override
 2 public View getView(int position, View convertView, ViewGroup parent) {
 3     ViewHolder holder;
 4     if (convertView == null) {
 5         convertView = inflater.inflate(R.layout.list_item, null);
 6         holder = new ViewHolder();
 7         ……
 8         convertView.setTag(holder);
 9     } else {
10         holder = (ViewHolder)convertView.getTag();
11     }
12 }
13
14 /**
15 * ViewHolder
16 *
17 * @author [email protected] 2013-08-01
18 */
19 private static class ViewHolder {
20
21     ImageView appIcon;
22     TextView  appName;
23     TextView  appInfo;
24 }

关于ListView缓存原理可见Android ListView缓存机制

4、其他点
(1) 用SurfaceView或TextureView代替普通View
SurfaceView或TextureView可以通过将绘图操作移动到另一个单独线程上提高性能。
普通View的绘制过程都是在主线程(UI线程)中完成,如果某些绘图操作影响性能就不好优化了,这时我们可以考虑使用SurfaceView和TextureView,他们的绘图操作发生在UI线程之外的另一个线程上。
因为SurfaceView在常规视图系统之外,所以无法像常规试图一样移动、缩放或旋转一个SurfaceView。TextureView是Android4.0引入的,除了与SurfaceView一样在单独线程绘制外,还可以像常规视图一样被改变。

(2) 使用RenderJavascript
RenderScript是Adnroid3.0引进的用来在Android上写高性能代码的一种语言,语法给予C语言的C99标准,他的结构是独立的,所以不需要为不同的CPU或者GPU定制代码代码。

(3) 使用OpenGL绘图
Android支持使用OpenGL API的高性能绘图,这是Android可用的最高级的绘图机制,在游戏类对性能要求较高的应用中得到广泛使用。
Android 4.3最大的改变,就是支持OpenGL ES 3.0。相比2.0,3.0有更多的缓冲区对象、增加了新的着色语言、增加多纹理支持等等,将为Android游戏带来更出色的视觉体验。

(4) 尽量为所有分辨率创建资源

减少不必要的硬件缩放,这会降低UI的绘制速度,可借助Android asset studio

5、布局调优工具
(1) hierarchy viewer
hierarchy viewer可以方便的查看Activity的布局,各个View的属性、measure、layout、draw的时间,如果耗时较多会用红色标记,否则显示绿色。
hierarchy viewer.bat位于<sdk>/tools/目录下。使用可见:Using Hierarchy Viewer, 示例图如下:

标注: hierarchy viewer目前在发布的商业版上处于安全考虑已经不可用:

To preserve security, Hierarchy Viewer can only connect to devices running a developer version of the Android system

  可参考http://lxfgrace.iteye.com/blog/1821869方案,just try

(2) layoutopt
layoutopt是一个可以提供layout及其层级优化提示的命令行,在sdk16以后已经被lint取代,在Windows->Show View->Other->Android->Lint Warnings查看lint优化提示,lint具体介绍可见Improving Your Code with lint

来源:http://www.trinea.cn/android/layout-performance/

时间: 2024-10-10 20:08:41

(转载)性能优化之布局优化的相关文章

Android 性能优化 三 布局优化ViewStub标签的使用

小黑与小白的故事,通过虚拟这两个人物进行一问一答的形式来共同学习ViewStub的使用 小白:Hi,小黑,ViewStub是什么?听说可以用来进行布局优化. 小黑:ViewStub 是一个隐藏的,不占用内存空间的视图对象,它可以在运行时延迟加载布局资源文件.(更多详细的API等信息可以查看官方文档ViewStub),计算机行业一向是实践里面出真知,下面用一个例子演示下效果. 小黑:说说概念只是为了概括性的了解下,还是用个实例来演示下.先来创建一个Activity中使用的布局文件,文件名是:act

Android性能优化之布局优化

由于Android系统对硬件的要求较高,并且上层应用都是用Java(效率要比C++低)编写的,对程序的优化就成了程序员的日常工作了:Android的优化 可以从以下几个地方下手:布局优化.数据库优化.使用异步加载数据.使用缓存技术.算法代码优化.使用线程池 先从比较简单的布局入手 程序目录结构 1.使用 <include>标签复用相同部分的布局文件,就是在一個而已文件中包含另一个布局 activity_main.xml <RelativeLayout xmlns:android=&quo

【转】Android性能优化之布局优化篇

转自:http://blog.csdn.net/feiduclear_up/article/details/46670433 Android性能优化之布局优化篇 分类: andorid 开发2015-06-29 16:28 238人阅读 评论(0) 收藏 举报 性能布局viewStubinclude布局优化 目录(?)[-] Hierarchy View检测布局嵌套层次 显示GPU过度绘制 懒加载布局 ViewStub Android Lint 工具 怎样才能写出优秀的Android App,是

Android性能优化之布局优化篇

怎样才能写出优秀的Android App,是每一个程序员追求的目标.那么怎么才能写出一个优秀的App呢?相信很多初学者也会有这种迷茫.一句话来回答这个问题:细节很重要.今天我们就从最基础的XML布局来谈谈怎么提高Android性能问题吧! 也许你经常会遇到比较复杂的布局,这种情况下,最简单的方法就是多层嵌套实现效果,但是最简单的方法是否是最优的方法呢? 这里需要打一个大大的问号?????经验告诉我们,往往简单的方法,得到的结果不是最优解,那么我们通过一个例子来研究一下怎么去优化我们的XML布局吧

Android Studido下的应用性能优化总结--布局优化

前言:一个应用的成功=产品设计*性能 ,再此我们不讨论一个应用的设计,那交给我们可爱又可恨的产品经理和UI设计师来决定!所以这里分步骤讨论如何提升一个应用的性能,这里先探讨布局优化问题. 布局优化 避免过度回执(Overdraw),由于过度绘制会浪费很多的CPU,GPU资源, 检查方法: 通过打开开发者选项–>GPU模式呈现分析–>在屏幕上显示为条形图.然后就会看到如下图的情况,最好用真机,模拟器回执有问题.  你可以观察一下绘制的条形图 tips:每一条柱状线都包含三部分,蓝色代表测量回执D

Android性能优化之一 布局优化

本文为Android性能优化--布局优化,主要介绍使用抽象布局标签(include, viewstub, merge).去除不必要的嵌套和View节点.减少不必要的infalte及其他Layout方面可调优点,顺带提及布局调优相关工具(hierarchy viewer和lint). 一.布局复杂度的优化 关于布局的优化,主要分两个大方向 实现相同界面效果并且层级结构相同时,选用何种Layout最好 在Android中单独的布局性能: FrameLayout>LinearLayout>Relat

Android 卡顿优化 3 布局优化

欲善其事, 先利其器. 分析布局, 就不得不用到Hierarchy Viewer了. 本文工具使用皆以GithubApp的详情界面RepoDetailActivity为例说明. 为了不影响阅读体验, 对应的布局文件activity_repo_detail.xml的代码放在文末 1, Hierarchy Viewer怎么用 Hierarchy发音 [美: 'ha??rɑrki] [英: 'ha??rɑ?k?] 层次结构的意思. 之前一直念不顺这个单词Hierarchy, 就简称为H Viewer了

android应用程序优化之布局优化

在我们开发APP时不仅要在代码实现上.做到对App的优化,而在我们的界面布局也有很多要优化的地方,假设布局写的非常low的话,系统载入布局的速度会十分的慢,使得用户的体验非常的不好.这篇文章主要是从我平时对布局的优化方面总结一下,我觉得常常能够用到的布局优化方面的一些技巧和手段. 1.降低布局的嵌套.这一点也是最重要的 搞android的都知道,android的整个UI布局文件最后也是要一层一层的解析成View对象的,假设层次太深的话,对导致递归的层次太深而极大的影响解析速度,所以,我们一定不能

Android-性能优化之布局优化

系统在渲染UI界面的时候会消耗大量的资源,一个好的UI不仅仅应该具有良好的视觉效果,更应该具有良好的使用体验,因此布局优化就显得非常的重要. 1.Android UI渲染机制 人眼所感觉到的流畅画面,需要画面的帧数达到40帧每秒到60帧每秒.在Android中,系统通过VSYNC信号触发对UI的渲染和重绘,其间隔时间是16ms.这个16ms其实就是1000ms中显示60帧的画面的单位时间,即1000/60.如果系统每次渲染的时间都保持在16ms之内,那么我们看到的UI界面是非常的流畅,但这也需要