Android性能优化之布局优化总结
2015-12-19 15:40
507 查看
布局优化,就是尽可能的减少布局文件的层级,布局结构层级少,绘制工作量也就少了,那么程序的性能自然就提高了。
如何进行布局优化?
1.首先五大布局中经常使用的RelativeLayout、LinearLayout,其次是FrameLayout,剩下的两种TableLayout一般偶尔使用一下,绝对布局由于屏幕适配的原因几乎没人使用。
1.RelativeLayout和LinearLayout都可以解决的,坚决使用LinearLayout,这是因为RelativeLayout的功能比较复杂,它的布局过程需要花费更多的Cpu时间。
2.LinearLayout需要嵌套多层布局才可实现的布局,可以考虑看看RelativeLayout,TableLayout能不能解决,可以就用RelativeLayout,TableLayout,因为嵌套更耗cpu。
3.同样FrameLayout可以解决的也不要使用RelativeLayout,FrameLayout和LinearLayout都是简单高效的布局。
2.其次使用标签.标签和标签
include主要用于布局的重用。
merge用于减少布局的层级,需要和include配合使用。
1.include 的用法
比如说下面一个布局include_layout,在多个地方使用。
那么在另一个布局中可以这样引用:
通过这种方式就不用把include_layout这个布局再重复写一遍。
使用include需要注意的地方
1.它只支持android:id和以android:layout_###开头的属性,其他属性不支持
2.include自身指定了id,它所引用的布局也指定了id,那么以include自身的id为准。
3.当使用android:layout_##属性的时候,必须要有android:layout_width和android:layout_height.
否则不会生效,就像下面这样;
2.merg的用法
上面布局一眼就能看出来是含有多余的层级,最外层是线性布局,include的布局也还是线性布局,所以说多余了。这里我们采用 Hieracrchy Viewer来看一下布局树信息。这个工具位于sdk\tools\hieracrchyviewer.bat.
可以看到setContentView添加进来的布局分支多余了,这样会降低性能。现在我们使用merge,修改include_layout,只是将LinearLayout替换成了merge,~~~xml片段如下:
同样使用include标签引入这个布局之后,运行程序,我们再次使用hierarchyviewer.bat查看,截图如下:
可以看到层次明显少了,这样性能就上来了。merge可以去掉多余的那一层布局。
3 ViewStub的用法
ViewStub继承了View,它非常轻量级,宽高都是0,本身不参与任何的布局和绘制过程,只有在需要加载的时候才会显示出来,一旦加载出来之后ViewStub就不存在了,取而代之的是他所加载的布局。另外,ViewStub不支持merge标签,两者不能共用。
比如我们还是要延迟加载include_layout原来这个布局(里面的merge要改成LinearLayout)xml里面的布局:
代码里面加载这个布局的方式有两种:
第二种方式好处可以返回你要加载的布局对象。
使用viewStub需要注意的地方:
1.它只支持android:id和以android:layout_###开头的属性,其他属性不支持
2.当View被加载出来之后,一旦设置android:inflatedId中的id会被设置成view的id(view自身带有的id会 被覆盖,没有设置android:inflateId的话,view还会使用自身的id)
3.当使用android:layout_##属性的时候,必须要有android:layout_width和android:layout_height.
否则不会生效,编译都不会通过。
4.ViewStub一旦加载完了view之后,它就会被从父容器里面移除,所以inflate()只能调用一次,否则会抛异常“ViewStub must have a non-null ViewGroup viewParent”,这一点可以从inflate的源代码中获知。
如何进行布局优化?
1.首先五大布局中经常使用的RelativeLayout、LinearLayout,其次是FrameLayout,剩下的两种TableLayout一般偶尔使用一下,绝对布局由于屏幕适配的原因几乎没人使用。
1.RelativeLayout和LinearLayout都可以解决的,坚决使用LinearLayout,这是因为RelativeLayout的功能比较复杂,它的布局过程需要花费更多的Cpu时间。
2.LinearLayout需要嵌套多层布局才可实现的布局,可以考虑看看RelativeLayout,TableLayout能不能解决,可以就用RelativeLayout,TableLayout,因为嵌套更耗cpu。
3.同样FrameLayout可以解决的也不要使用RelativeLayout,FrameLayout和LinearLayout都是简单高效的布局。
2.其次使用标签.标签和标签
include主要用于布局的重用。
merge用于减少布局的层级,需要和include配合使用。
1.include 的用法
比如说下面一个布局include_layout,在多个地方使用。
<?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="wrap_content" android:orientation="vertical" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="第一个按钮" android:textColor="@android:color/black" android:textSize="20sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="第二个按钮" android:textColor="@android:color/black" android:textSize="20sp" /> </LinearLayout>
那么在另一个布局中可以这样引用:
<?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" > <include layout="@layout/include_layout" /> </LinearLayout>
通过这种方式就不用把include_layout这个布局再重复写一遍。
使用include需要注意的地方
1.它只支持android:id和以android:layout_###开头的属性,其他属性不支持
2.include自身指定了id,它所引用的布局也指定了id,那么以include自身的id为准。
3.当使用android:layout_##属性的时候,必须要有android:layout_width和android:layout_height.
否则不会生效,就像下面这样;
<?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" > <include android:id="@+id/new_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" layout="@layout/include_layout" /> </LinearLayout>
2.merg的用法
上面布局一眼就能看出来是含有多余的层级,最外层是线性布局,include的布局也还是线性布局,所以说多余了。这里我们采用 Hieracrchy Viewer来看一下布局树信息。这个工具位于sdk\tools\hieracrchyviewer.bat.
可以看到setContentView添加进来的布局分支多余了,这样会降低性能。现在我们使用merge,修改include_layout,只是将LinearLayout替换成了merge,~~~xml片段如下:
<?xml version="1.0" encoding="utf-8"?> <merge xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/include_id" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#ff0099" android:orientation="vertical" > <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="第一个按钮" android:textColor="@android:color/black" android:textSize="20sp" /> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="第二个按钮" android:textColor="@android:color/black" android:textSize="20sp" /> </merge>
同样使用include标签引入这个布局之后,运行程序,我们再次使用hierarchyviewer.bat查看,截图如下:
可以看到层次明显少了,这样性能就上来了。merge可以去掉多余的那一层布局。
3 ViewStub的用法
ViewStub继承了View,它非常轻量级,宽高都是0,本身不参与任何的布局和绘制过程,只有在需要加载的时候才会显示出来,一旦加载出来之后ViewStub就不存在了,取而代之的是他所加载的布局。另外,ViewStub不支持merge标签,两者不能共用。
比如我们还是要延迟加载include_layout原来这个布局(里面的merge要改成LinearLayout)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" > <ViewStub android:id="@+id/stub_import" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" android:background="#00ff00" android:inflatedId="@+id/inflatedId" android:layout="@layout/include_layout" /> </LinearLayout>
代码里面加载这个布局的方式有两种:
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ViewStub stub = (ViewStub) findViewById(R.id.stub_import); // 第一种方式 // stub.setVisibility(View.VISIBLE); // 第二种方式 View inflateView = stub.inflate();//返回的你要加载的那个布局对象 }
第二种方式好处可以返回你要加载的布局对象。
使用viewStub需要注意的地方:
1.它只支持android:id和以android:layout_###开头的属性,其他属性不支持
2.当View被加载出来之后,一旦设置android:inflatedId中的id会被设置成view的id(view自身带有的id会 被覆盖,没有设置android:inflateId的话,view还会使用自身的id)
3.当使用android:layout_##属性的时候,必须要有android:layout_width和android:layout_height.
否则不会生效,编译都不会通过。
4.ViewStub一旦加载完了view之后,它就会被从父容器里面移除,所以inflate()只能调用一次,否则会抛异常“ViewStub must have a non-null ViewGroup viewParent”,这一点可以从inflate的源代码中获知。
public View inflate() { //首先获取父容器对象 final ViewParent viewParent = getParent(); //第一次肯定不是空,而且属于五大布局,这个条件为true if (viewParent != null && viewParent instanceof ViewGroup) { if (mLayoutResource != 0) { final ViewGroup parent = (ViewGroup) viewParent; final LayoutInflater factory; if (mInflater != null) { factory = mInflater; } else { factory = LayoutInflater.from(mContext); } //使用布局加载器加载了这个view对象,但没有添加到父容器中 final View view = factory.inflate(mLayoutResource, parent, false); //如果android:inflateId有被赋值的话,这个条件为true if (mInflatedId != NO_ID) { //重新为为view设置inflatedId的id view.setId(mInflatedId); } //获取这个viewstub对象在父容器中的位置索引index final int index = parent.indexOfChild(this); /** *将这个viewstub对象从父容器里面移除,这个viewstub对象不再父容器中, *再次条用inflate()会破异常, *因为方法最开始的 ViewParent viewParent = getParent(),是空值, *破最下面的异常 */ parent.removeViewInLayout(this); //将下载好的view添加到父容器中 final ViewGroup.LayoutParams layoutParams = getLayoutParams(); if (layoutParams != null) { parent.addView(view, index, layoutParams); } else { parent.addView(view, index); } mInflatedViewRef = new WeakReference<View>(view); if (mInflateListener != null) { mInflateListener.onInflate(this, view); } return view; } else { throw new IllegalArgumentException("ViewStub must have a valid layoutResource"); } } else { throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent"); } }
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories