App 性能优化系列:
Android App 性能优化(二)----内存泄露(Memory Leak)
Android App 性能优化(一)----布局优化
一. 概述
布局优化在 Android 性能优化中占有举足轻重的作用, 如果布局层次复杂,嵌套过深, 这样的布局就会导致在测量绘制的时候更耗时, 占用更多内存, 很容易就会出现卡顿. 如果布局层次分明合理, 没有冗余View的布局, 不仅可以提高加载速度, 提供一个良好的用户体验, 还能使我们的代码更容易维护和重用.
二. 具体的优化方案
(1). 选择合适的 ViewGroup
优先考虑使用
ConstraintLayout
,这也是google 推荐使用的布局ConstraintLayout
允许你在不嵌套的情况下复杂的布局,它与RelativeLayout
非常相似,所有的view都依赖于兄弟控件和父控件的相对关系,但是ConstraintLayout
比RelativeLayout
更加灵活.
目前通过 Android Studio 新建一个 layout xml 时默认的就是ConstraintLayout
, 使用它可以有效减少了布局的层级,大幅提高性能.
由于 Android 的碎片化程度高,手机屏幕尺寸众多,使用ConstraintLayout
能构建出多屏幕适配性更好的布局.
ConstraintLayout使用介绍尽量多使用
RelativeLayout
和LinearLayout
,不要使用绝对布局AbsoluteLayout
;
在布局层次一样的情况下, 建议使用LinearLayout
代替RelativeLayout
, 因为LinearLayout
性能要稍高一点;
LinearLayout 比 RelativeLayout 快的根本原因是 RelativeLayout 需要对其子View 进行两次 measure 过程, 而 LinearLayout 则只需一次 measure 过程,所以显然会快于 RelativeLayout,但是如果 LinearLayout 中有
weight
属性,则也需要进行两次measure,但即便如此,应该仍然会比 RelativeLayout 快一点。
-
RelativeLayout
的子View如果高度和RelativeLayout
不同,会引发效率问题,当子View很复杂时,这个问题会更加严重, 如果可以,尽量使用padding
代替margin
. - 在层级深度相同的情况下, 优先使用
LinearLayout
和FrameLayout
而不是RelativeLayout
。
(2). 使用include, merge, ViewStub 标签
1. **重用布局 **<include/>
<include/>
标签可将布局中的公共部分提取出来供其他layout
,以实现布局复用的目的, 这样可以减少项目中重复的布局, 更能减少程序员的工作量.
比如include_progressbar.xml
这个布局app的很多页面都会用到,这时就可以将它抽出来, 以便达到重用的目的;
include_progressbar.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center">
<ProgressBar
android:id="@+id/pb"
android:layout_width="50dp"
android:layout_height="50dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:text="加载中..."/>
</LinearLayout>
在
activity_main.xml
中使用:
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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="cjlcom.includetest.MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World! Hello World! Hello World! Hello World!" />
<include
android:id="@+id/pb_main"
layout="@layout/include_progressbar">
</include>
</android.support.constraint.ConstraintLayout>
2. 合并布局<merge/>
有时我们在使用
<include/>
后可能会导致出现相同ViewGroup
的嵌套, 比如我们使用<include/>
要引入的布局的根布局为FrameLayout
, 并且引入之后该布局的父布局也是FrameLayout
, 这时最终的布局就会出现两层相同FrameLayout布局, 这种 layout 节点是多余的,会导致解析变慢,解决办法就是通过<merge/>
标签去掉这多余的一层FrameLayout
节点.
还有一种比较特殊的情况就是根布局是FrameLayout
且不需要设置background或padding等属性,可以用merge代替,因为Activity内容试图的parent view就是个FrameLayout,所以可以用merge消除只剩一个。
3. 按需加载<ViewStub/>
<viewstub/>
标签同<include/>
标签都可以用来引入一个外部布局,区别是<viewstub/>
引入的布局默认不会去绘制,从而在解析layout时加快速度和减少内存开销.
<viewstub/>
常用来引入那些默认不会显示,只在特殊情况下显示的布局,如进度条布局、网络加载失败或者重试等刷新布局、信息出错出现的提示布局等.
还有一种方法就是不需要立即加载的布局,设置visibility为GONE,系统会跳过,不加载, 这种方法和<viewstub/>
区别后续说明.
(3). 使用<Space/>
控件
参考
[1] http://blog.csdn.net/hejjunlin/article/details/51159419