布局優(yōu)化主要從以下幾點(diǎn)進(jìn)行著手
- 減少布局層次 和 復(fù)雜度
- 優(yōu)化繪制流程
- 按需加載布局
減少布局層次 和 復(fù)雜度
- 首先我們可以通過以下工具分析界面布局的結(jié)構(gòu)
-
查看布局樹工具:Hierarchy Viewer --> SDK tools下/ 或者使用AS的 Tools-->Layout Inspector
除此之外我們可以查看界面的繪制分析
三個(gè)點(diǎn)分別表示:Measure , layout , draw
Mearsure 紅:嵌套R(shí)elativeLayout空繁,或者嵌套LinearLayout 使用了weight 屬性
Layout 紅:布局嵌套層次太深
Draw 紅:自定義view 繪制有問題
-
打開手機(jī)的debug模式下Debug GPU overdraw可以查看過度繪制的區(qū)域
- 通過以上的布局分析可以使用以下方法減少布局的層次和復(fù)雜度
- 使用合適的布局結(jié)構(gòu)尚骄,減少不必要的布局嵌套,一般的建議規(guī)則如下
1.盡量多使用 ConstraintLayout茧球、RelativeLayout麸澜、LinearLayout
2.盡量使用 ConstraintLayout
3.在布局的層級(jí)相同的情況下税娜,使用 LinearLayout 代替 RelativeLayout
4.在布局復(fù)雜或者層級(jí)過深的時(shí)候,使用 RelativeLayout 代替 LinearLayout 使界面層級(jí)扁平化拴事,降低層級(jí)
- 通過使用 include merge 復(fù)用布局践剂,減少布局層次
- 排查background,減少不必的背景色設(shè)置溉知,減少過度繪制
移除window 的背景色\ListView 與 Item\ViewPager 與 Fragment
// 方式1:在應(yīng)用的主題中添加如下的一行屬性
<item name="android:windowBackground">@android:color/transparent</item>
<!-- 或者 -->
<item name="android:windowBackground">@null</item>
// 方式2:在 BaseActivity 的 onCreate() 方法中使用下面的代碼移除
getWindow().setBackgroundDrawable(null);
<!-- 或者 -->
getWindow().setBackgroundDrawableResource(android.R.color.transparent);
優(yōu)化繪制流程
- 對(duì)onDraw進(jìn)行優(yōu)化
- 減少onDraw中局部變量的聲明 -- 由于被頻繁調(diào)用變量的生成和銷毀會(huì)造成一定的開銷陨瘩,局部變量過多會(huì)造成系統(tǒng)的消耗
- 減少onDraw 中耗時(shí)操作 -- 由于官方建議每幀繪制頻率為60fsp腕够,即要求每幀繪制時(shí)間<=16sm,Android 系統(tǒng)每隔16ms發(fā)出ASYNC信號(hào)舌劳,出發(fā)對(duì)UI進(jìn)行渲染
android 官方文檔:https://developer.android.google.cn/topic/performance/rendering
可以使用debug 中的工具(Profile GPU Rendering)分析每幀繪制的時(shí)間帚湘,推薦文章
http://www.reibang.com/p/6b715f3d47e4;
也可以通過將內(nèi)容輸出到文件中進(jìn)行分析蒿囤,推薦文章:
https://www.cnblogs.com/sinkv/p/9773256.html
- 使用局部繪制api
// 規(guī)定繪制區(qū)域客们,防止其他區(qū)域過度繪制
canvas.save();
canvas.clipRect(xx,xx,xx,xx);
canvas.restore();
//可以使用canvas.quickreject()來判斷是否沒和某個(gè)矩形相交,從而跳過那些非矩形區(qū)域內(nèi)的繪制操作
按需加載布局
- 使用viewStub 按需加載布局材诽,可以提高view 初始加載的速度
新加:
-
除了以上方法我們還可以通過使用Lint 工具進(jìn)行排查,一般我們需要關(guān)注的Lint 排查點(diǎn):
- 不要阻塞UI線程恒傻,將耗時(shí)任務(wù)放到子線程中操作脸侥,可以使用DDMS中的TraceView 進(jìn)行分析,查看主線程中的耗時(shí)操作
- 使用AsyncLayoutInflater 異步加載布局,不過再使用中存下來一下問題
- 不能設(shè)置LayoutInflater.Factory/Factory2
- 線程安全問題
推薦文章
Android AsyncLayoutInflater 源碼解析
Android AsyncLayoutInflater 限制及改進(jìn)
- 使用Factory 監(jiān)控view 的創(chuàng)建時(shí)間
LayoutInflaterCompat.setFactory2(getLayoutInflater(), new LayoutInflater.Factory2() {
@Nullable
@Override
public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) {
//1.配合getDelegate().createView來做高版本控件的兼容適配盈厘。
//2.單個(gè)View創(chuàng)建耗時(shí)統(tǒng)計(jì)睁枕。
long time = System.currentTimeMillis();
View view = getDelegate().createView(parent, name, context, attrs);
Log.i("TAG", name + " cost: " + (System.currentTimeMillis() - time));
return view;
}
@Nullable
@Override
public View onCreateView(@NonNull String name, @NonNull Context context, @NonNull AttributeSet attrs) {
return null;
}
});
2020-03-11 16:43:07.389 17078-17078/com.stan.topnews I/Perf: Connecting to perf service.
2020-03-11 16:43:07.567 17078-17078/com.stan.topnews I/perf: LinearLayout cost: 13
2020-03-11 16:43:07.569 17078-17078/com.stan.topnews I/perf: ViewStub cost: 0
2020-03-11 16:43:07.634 17078-17078/com.stan.topnews I/perf: TextView cost: 16
2020-03-11 16:43:07.637 17078-17078/com.stan.topnews I/perf: TextView cost: 3