您的位置:首页 > 移动开发 > Android开发

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,在多个地方使用。

<?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");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 布局 优化