android布局优化的目标:
- 使屏幕绘制低延迟
- 保证流程稳定的帧率来避免卡顿
优化布局的技巧:
- 减少布局层次
下图是一个简单的app View,其中包含一些View。搭建这些view的时候,一定要留意屏幕右上角的组件树(Component Tree)。套嵌的子view越深,组件树就越复杂,渲染起来也就越费时间。
对于app里的每一个view,android系统都会经过三部曲来渲染:measure,layout,draw。可以在脑中回想下你搭建的view的xml布局文件结构,measure从最顶部的节点开始,顺着layout树形结构依次往下:测量每个view需要在屏幕当中展示的尺寸大小。每个子节点都需要向自己的父节点提供自己的尺寸来决定展示的位置,遇到冲突的时候,父节点可以强制子节点重新measure(由此可能导致measure的时间消耗为原来的2-3倍)。这就是为什么扁平的view结构会性能更好。节点所处位置越深,套嵌带来的measure越多,计算就会越费时。
- 删除无用布局
- 不要嵌套多个使用layout_weight属性的LinearLayout
- Android lint
- Hierarchy Viewr
-
<merge />
什么情况考虑使用Merge?
子视图不需要指定任何针对父视图的布局属性,例子中TextView仅仅需要直接添加到父视图上用于显示就行。例子:
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.kevinwang.test.TestActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:text="Test Merge!"/>
</RelativeLayout>
图1是使用RelativLayout时显示的层次结构。
布局文件修改内容如下:
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.kevinwang.test.TestActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="25sp"
android:text="Test Merge!"/>
</merge>
图2是使用merge时显示的层次结构。
Merge标签有什么使用限制?
只能作为XML布局的根标签使用。
- ViewStub标签
ViewStub 是一个隐藏的,不占用内存空间的视图对象,它可以在运行时延迟加载布局资源文件。例子:
先来创建一个Activity中使用的布局文件,文件名是:activity_test.xml
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.kevinwang.test.TestActivity">
<Button
android:id="@+id/show_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="显示"/>
<ViewStub
android:id="@+id/viewstub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout="@layout/sub_layout"
/>
<Button
android:id="@+id/hide_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="隐藏"/>
</LinearLayout>
android:layout="@layout/sub_layout"引入一个新的布局sub_layout.xml代码如下:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ViewStub中包含的TextVeiw"/>
</LinearLayout>
添加Button点击事件:
public class TestActivity extends Activity {
private Button showButton;
private Button hideButton;
private ViewStub viewStub;
private View view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
viewStub = (ViewStub) findViewById(R.id.viewstub);
showButton = (Button)findViewById(R.id.show_button);
showButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (view == null) {
view = viewStub.inflate();//注意inflate方法不能被调用两次
}
else {
view.setVisibility(View.VISIBLE);
}
}
});
hideButton =(Button)findViewById(R.id.hide_button);
hideButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
view.setVisibility(View.GONE);
if (view == null) {
Log.i("hide_layout", "隐藏布局已经消失");
}
}
});
}
}
打开应用时界面如下图:
点击显示按钮时界面如下:
点击隐藏恢复打开应用时的界面
关于布局优化更多内容可参考MrPeakTech