Android性能优化之布局优化
2016-06-01 15:00
501 查看
本文主要介绍布局标签(include、viewstub、merge),去除不必要的嵌套和View节点,减少不必要的infalte及其他Layout方面可调优点,顺带体积布局调优相关工具(hierarchy viewer和lint)
抽象布局嵌套
例:<?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" >
<ListView
android:id="@+id/simple_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/dp_80" />
<include layout="@layout/foot.xml" />
</RelativeLayout>其中include引入的foot.xml为共用的页面底部,代码如下:
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" >
……
<ViewStub
android:id="@+id/network_error_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/network_error" />
</RelativeLayout>其中network_error.xml为只能在网络错误时才需要显示的布局,默认不会被解析。
viewstub标签大部分属性同include标签类似。
通过viewstub的原理我们可以知道将一个view设置为GONE不会被解析,从而提高layout解析速度,二VISIBLE和INVISIBLE这两个可见性属性会被正常解析。
merge标签可用于两种类型的情况:
布局顶结点是FrameLayout且不需要设置background或padding等属性,可以用merge代替,因为Activity内容视图就是个FrameLayout,所以可以用merge消除只剩一个。
某布局作为子布局被其他布局include时,使用merge当做该布局的顶结点,这样在被引入时丁结点会自动被忽略,而将子节点全部并到主布局中。
以<include>标签为例,用hierarchy viewer查看main.xml布局如下图:
可以发现多了一层没必要的RelativeLayout,将foot.xml中RelativeLayout改为merge,如下:<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40"
android:layout_above="@+id/text"/>
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40"
android:layout_alignParentBottom="true"
android:text="@string/app_name" />
</merge>运行后再次使用hierarchy viewer查看main.xml布局如下图:
这样就没有多余的RelativeLayout节点了。
去除不必要的嵌套和view节点
首次不需要使用的节点设置为GONE或者使用<viewstub>
使用RelativeLayout代替LinearLayout,大约在4.0以前,新建工程的默认main.xml中顶节点是LinearLayout,而在之后已经改为RelativeLayout,因为RelativeLayout性能更优,且可以简单实现LinearLayout嵌套才能实现的布局。
4.0及以上Android版本可以通过:设置->开发者选项->显示布局边界打开页面布局显示,看看是否有不必要的节点和嵌套。4.0以下版本可以通过hierarchy viewer查看。
SurfaceView或TextureView可以通过将绘图操作移动到另一个单独线程上提高性能,普通View的绘制过程是在UI线程中完成,如果某些绘图操作影响性能就不好优化了。这时我们可以考虑使用SurfaceView和TextureView,他们的绘图操作发生在UI线程之外的另一个线程上。
因为SurfaceView在常规视图系统之外,所以无法像常规视图一样移动,缩放或旋转。TextureView是Android4.0引入的,除了与SurfaceView一样在单独线程绘制外,还可以像常规视图一样被改变。
尽量为所有的分辨率创建资源,减少不必要的硬件缩放,这会降低UI的绘制速度,可借助Android asset studio
抽象布局嵌套
<include>标签
include标签常用于将布局中的公共部分提取出来供其他layout共用,以实现布局模块化,在布局编写方面提供了大大的便利。例:<?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" >
<ListView
android:id="@+id/simple_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/dp_80" />
<include layout="@layout/foot.xml" />
</RelativeLayout>其中include引入的foot.xml为共用的页面底部,代码如下:
<?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" > <Button android:id="@+id/button" android:layout_width="match_parent" android:layout_height="@dimen/dp_40" android:layout_above="@+id/text"/> <TextView android:id="@+id/text" android:layout_width="match_parent" android:layout_height="@dimen/dp_40" android:layout_alignParentBottom="true" android:text="@string/app_name" /> </RelativeLayout><include>标签唯一需要的属性石layout属性,指定需要包含的布局文件。可以的定义android:id和android:layout_*属性来覆盖被引入布局根节点的对应属性。注意重新定义android:id后,子布局的顶节点就变化了。
<viewstub>标签
viewstub标签同include标签一样可以用来引入一个外部布局,不同的是,viewstub引入的布局默认不会扩张,即既不会占用显示也不会占用位置,从而在解析layout时节省cpu和内存。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" >
……
<ViewStub
android:id="@+id/network_error_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout="@layout/network_error" />
</RelativeLayout>其中network_error.xml为只能在网络错误时才需要显示的布局,默认不会被解析。
<?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" > <Button android:id="@+id/network_setting" android:layout_width="@dimen/dp_160" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:text="@string/network_setting" /> <Button android:id="@+id/network_refresh" android:layout_width="@dimen/dp_160" android:layout_height="wrap_content" android:layout_below="@+id/network_setting" android:layout_centerHorizontal="true" android:layout_marginTop="@dimen/dp_10" android:text="@string/network_refresh" /> </RelativeLayout>在java中通过(Viewstub)findViewById(id)找到ViewStub,通过stub.inflate()展开ViewStub然后得到子View
private View networkErrorView; private void showNetError() { // not repeated infalte if (networkErrorView != null) { networkErrorView.setVisibility(View.VISIBLE); return; } ViewStub stub = (ViewStub)findViewById(R.id.network_error_layout); networkErrorView = stub.inflate(); Button networkSetting = (Button)networkErrorView.findViewById(R.id.network_setting); Button refresh = (Button)findViewById(R.id.network_refresh); } private void showNormal() { if (networkErrorView != null) { networkErrorView.setVisibility(View.GONE); } }在上面showNetError()中展开了ViewStub,同时我们对networkError进行保存这样下次不要继续inflate。这就是后面第三部分提到的减少不必要的infalte。
viewstub标签大部分属性同include标签类似。
通过viewstub的原理我们可以知道将一个view设置为GONE不会被解析,从而提高layout解析速度,二VISIBLE和INVISIBLE这两个可见性属性会被正常解析。
<merge>标签
在使用了include后可能导致布局嵌套过多,对于不必要的layout节点,从而导致解析变慢,不必要的节点和嵌套可通过hierarchy viewer(设置->开发者选项->显示布局边界)查看。merge标签可用于两种类型的情况:
布局顶结点是FrameLayout且不需要设置background或padding等属性,可以用merge代替,因为Activity内容视图就是个FrameLayout,所以可以用merge消除只剩一个。
某布局作为子布局被其他布局include时,使用merge当做该布局的顶结点,这样在被引入时丁结点会自动被忽略,而将子节点全部并到主布局中。
以<include>标签为例,用hierarchy viewer查看main.xml布局如下图:
可以发现多了一层没必要的RelativeLayout,将foot.xml中RelativeLayout改为merge,如下:<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40"
android:layout_above="@+id/text"/>
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="@dimen/dp_40"
android:layout_alignParentBottom="true"
android:text="@string/app_name" />
</merge>运行后再次使用hierarchy viewer查看main.xml布局如下图:
这样就没有多余的RelativeLayout节点了。
去除不必要的嵌套和view节点
首次不需要使用的节点设置为GONE或者使用<viewstub>
使用RelativeLayout代替LinearLayout,大约在4.0以前,新建工程的默认main.xml中顶节点是LinearLayout,而在之后已经改为RelativeLayout,因为RelativeLayout性能更优,且可以简单实现LinearLayout嵌套才能实现的布局。
4.0及以上Android版本可以通过:设置->开发者选项->显示布局边界打开页面布局显示,看看是否有不必要的节点和嵌套。4.0以下版本可以通过hierarchy viewer查看。
其他点
用SurfaceView或TextureView代替普通ViewSurfaceView或TextureView可以通过将绘图操作移动到另一个单独线程上提高性能,普通View的绘制过程是在UI线程中完成,如果某些绘图操作影响性能就不好优化了。这时我们可以考虑使用SurfaceView和TextureView,他们的绘图操作发生在UI线程之外的另一个线程上。
因为SurfaceView在常规视图系统之外,所以无法像常规视图一样移动,缩放或旋转。TextureView是Android4.0引入的,除了与SurfaceView一样在单独线程绘制外,还可以像常规视图一样被改变。
尽量为所有的分辨率创建资源,减少不必要的硬件缩放,这会降低UI的绘制速度,可借助Android asset studio
相关文章推荐
- 深入理解PHP7内核之FAST_ZPP
- Flex 性能优化常用手法总结
- Ruby中require、load、include、extend的区别介绍
- oracle 性能优化建议小结
- Lua性能优化技巧(一):前言
- Lua性能优化技巧(五):削减、重用和回收
- Lua性能优化技巧(三):关于表
- Lua性能优化技巧(四):关于字符串
- SQL Server 2016 查询存储性能优化小结
- MySQL性能优化 出题业务SQL优化
- vbscript include的办法实现代码第1/2页
- PowerShell脚本性能优化技巧总结
- SQL SERVER性能优化综述(很好的总结,不要错过哦)第1/3页
- MySQL Index Condition Pushdown(ICP)性能优化方法实例
- Ajax无刷新分页的性能优化方法
- SQLServer中merge函数用法详解
- 解析C++编程中的#include和条件编译
- PHP脚本中include文件出错解决方法
- Flex include和import ActionScript代码
- 简单谈谈PHP中的include、include_once、require以及require_once语句