1概述
以 密卷點(diǎn)評(píng)中的標(biāo)記功能為例校摩,
優(yōu)化前后的幀率對(duì)比
可以看到大約 15 幀的提升。
2 分析方法
2.1 打印幀率
評(píng)估一個(gè)應(yīng)用的流暢度阶淘,除了主觀感受外衙吩,定量的幀率測量是很有必要的。從4.4 之后都支持通過設(shè)置屬性來打開幀率輸出溪窒。
具體操作:
? setprop debug.sf.fps 1
? stop;start(5.0 以后不需要坤塞,但是需要退到主界面滑動(dòng),直到下述 log 輸出幀率)
? logcat –s SurfaceFlinger 觀察幀率
從手寫標(biāo)記這個(gè)應(yīng)用中可以看到澈蚌,原始的幀率在 20 幀左右
2.2 瓶頸分析
分析瓶頸摹芙,我們可以利用谷歌提供的 DDMS 工具進(jìn)行。首先我們使用 systrace 獲取幾項(xiàng)圖形系統(tǒng)相關(guān)的數(shù)據(jù)惜浅。
具體操作:
? 執(zhí)行 adb root瘫辩,確保 adb 具有 root 權(quán)限
?點(diǎn) 擊OK之 后 , 開 始 進(jìn) 行 手 寫 操 作 坛悉, 采 集 時(shí) 間 到 了 之 后 伐厌, 會(huì) 在
? 使用 chrome 瀏覽器打開該文件
? 查看被測進(jìn)程
? 測量 draw 時(shí)間
可以看到一幀的繪制時(shí)間在 45ms 左右裸影,排除 input 派發(fā)等其他操作挣轨,折算一下,幀率大約就是1000ms/45ms≈20fps轩猩,超出了 60fps 下所要求的一幀 16ms卷扮〉磁欤可以認(rèn)為,draw 是瓶頸所在晤锹。
2.3 分析熱點(diǎn)函數(shù)
熱點(diǎn)函數(shù)我們同樣使用 DDMS 自帶的 Method Profiling 工具
具體操作:
? 開始滑動(dòng)摩幔,采集數(shù)據(jù)
?停止采集。
? 這里建議在點(diǎn)擊 start 之前就開始滑動(dòng)鞭铆,因?yàn)橄到y(tǒng)默認(rèn)只能采集 8MB 的數(shù)據(jù)或衡,超過 8M 是不會(huì)繼續(xù)采集的。
? 展開之后车遂,不需要使用列表中的統(tǒng)計(jì)功能封断,已經(jīng)能夠看到幾個(gè)耗時(shí)的區(qū)塊
? 點(diǎn)擊幾個(gè)色塊,可以看到舶担,熱點(diǎn)函數(shù)集中在
? 其中以下的紅框調(diào)用是需要分析的
?做減法評(píng)估大頭
om.eebbk.themeplayer.ScrollViewLinearLayout.drawCacheBackground(Canvas)----去掉坡疼,提升 5幀
com.eebbk.themeplayer.ScrollViewLinearLayout.drawDrawingStroke(Canvas)--------去掉,提升 10幀
? 之后會(huì)出現(xiàn)一個(gè)問題衣陶,去掉上述函數(shù)調(diào)用之后柄瑰,仍然沒有辦法達(dá)到 60 幀的滿幀。因此將注意力集中到
? 至此祖搓,工具已經(jīng)沒有辦法提供更多的有用信息狱意。
2.4 分析繪制代碼
? 打開 draw 相關(guān) log 開關(guān)
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -110,7 +110,7 @@ public final class ViewRootImpl implements ViewParent,
private static final boolean DBG = false;
private static final boolean LOCAL_LOGV = false;
/** @noinspection PointlessBooleanExpression*/
- private static final boolean DEBUG_DRAW = false || LOCAL_LOGV;
+ private static final boolean DEBUG_DRAW = true || LOCAL_LOGV;
? 查看 log,可以發(fā)現(xiàn)
Invalidate child: Rect(118, 170 - 1536, 1952)
臟區(qū)非常大拯欧,也就是每次需要重繪的區(qū)域非常大。
對(duì)比滿幀的草稿紙應(yīng)用财骨,Invalidate child: Rect(532, 1004 - 547, 1023)這個(gè)臟區(qū)就很小镐作。
? 繼續(xù)在 invalidate 的路徑上(函數(shù) invalidateInternal)添加 log
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11803,6 +11803,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
if (p != null && ai != null && l < r && t < b) {
final Rect damage = ai.mTmpInvalRect;
damage.set(l, t, r, b);
+ //debug();
+ Log.e("cw","View:" + this + " dirty {" + l + ", " + t + ", " + r + ", " + b + "}", new
Throwable());
p.invalidateChild(this, damage);
}
對(duì) 比 密 卷 和 草 稿 紙 兩 個(gè) 應(yīng) 用 , 可 以 發(fā) 現(xiàn) 草 稿 紙 調(diào) 用 了
com.eebbk.draftpaper.slate.Slate.invalidate(Rect)隆箩,是帶矩形參數(shù)的该贾,因此臟區(qū)可以控制的很小。
而密卷調(diào)用的是com.eebbk.themeplayer.ScrollViewLinearLayout.drawStroke(Bitmap, Bitmap, int,
int)中的 postInvalidate捌臊,不帶參數(shù)會(huì)導(dǎo)致整個(gè) ScrollViewLinearLayout 重繪杨蛋。
3 應(yīng)對(duì)方法
根據(jù)上述分析,瓶頸在于 draw 的臟區(qū)過大理澎,導(dǎo)致重繪耗時(shí)逞力。因此至少可以有兩處優(yōu)化:
?可以參照草稿紙應(yīng)用,減小臟區(qū)
?將 com.eebbk.themeplayer.ScrollViewLinearLayout.drawCacheBackground(Canvas)做適當(dāng)優(yōu)化糠爬,避免每
次 draw 都重新繪制這個(gè)靜止的背景寇荧。