Android 性能個(gè)案研究
Falcon Pro
我最近在我的Nexus 4上安裝了Falcon Pro,一個(gè)新的Twitter客戶端。我真的很喜歡使用這個(gè)應(yīng)用程序,但我在使用它時(shí)注意到了某些地方存在一些問(wèn)題,看起來(lái)滾動(dòng)主時(shí)間軸并沒(méi)有得到非常穩(wěn)定的幀率。我深鉆了一下我每天工作所用工具和技術(shù)中的一些,我能很快地找到一些Falcon Pro 并不如它本可以表現(xiàn)得那么好的原因。
我在這篇文章里的目的是告訴你如何追蹤和修復(fù)應(yīng)用程序中的性能問(wèn)題,即使你沒(méi)有它的源代碼。所有你需要的只是一份最新的Android 4.2 SDK –新的ADT bundle使設(shè)置變得簡(jiǎn)易。我極力推薦你下載這個(gè)應(yīng)用程序來(lái)親自應(yīng)用這里描述的技術(shù)。對(duì)你來(lái)說(shuō)不幸的是Falcon Pro是款付費(fèi)應(yīng)用,因此我將給您提供你可以下載的各種文件的鏈接來(lái)跟隨我的分析。
關(guān)于性能
Android 4.1把重點(diǎn)放在Butter項(xiàng)目的性能上,它帶來(lái)了新的性能分析工具,如systrace。Android 4.2不提供象systrace那么顯著的工具,只是提供了對(duì)你的工具箱的一些有益補(bǔ)充。在本文的后面你會(huì)發(fā)現(xiàn)這些新工具中的一個(gè)。
性能分析往往是一個(gè)復(fù)雜的任務(wù),需要大量的經(jīng)驗(yàn)和對(duì)某些工具、硬件、API的深入的知識(shí)等等。經(jīng)驗(yàn)使我能只用幾分鐘就進(jìn)行在這里展示的分析——你可以在我十二月一日的Twitter stream上看到它“實(shí)時(shí)”發(fā)生。你可能要多試幾次才會(huì)感覺(jué)這種工作很容易。
證實(shí)我的懷疑
關(guān)于性能操作,牢記最重要的一件事就是始終用測(cè)試去驗(yàn)證你的行為。即使Falcon Pro 在Nexus4上運(yùn)行幀率下降看起來(lái)很明顯,我還是需要確認(rèn)一下。因此,我將應(yīng)用安裝到一部提供不同于Nexus性能概況并且比Nexus4更強(qiáng)大的Nexus7上。Nexus 7提供了一個(gè)有趣的更有優(yōu)勢(shì)的性能分析工具,我們以后再談。
在Nexus 7安裝應(yīng)用程序并沒(méi)有什么區(qū)別,我仍能看到幀率下降。應(yīng)用甚至顯得稍差。為了描述這個(gè)問(wèn)題,我決定用4.1以后引入的“GPU呈現(xiàn)模式分析”工具。你可以在應(yīng)用設(shè)置下的“開(kāi)發(fā)者選項(xiàng)”中找到它。
如果“開(kāi)發(fā)者選項(xiàng)”在你的android4.2設(shè)備上不能使用,找到“關(guān)于手機(jī)”或者“關(guān)于平板”勾選底部的7的倍數(shù)構(gòu)建選項(xiàng)。
當(dāng)選項(xiàng)打開(kāi)后, 系統(tǒng)會(huì)保持跟蹤每個(gè)窗口繪制最后128幀所耗費(fèi)的時(shí)間。使用這個(gè)工具你必須首先結(jié)束掉應(yīng)用– android將來(lái)的版本將擺脫這個(gè)限制。
方法說(shuō)明:除非另有規(guī)定,本分析每個(gè)測(cè)量是通過(guò)每次緩慢滾動(dòng)主時(shí)間軸上下幾點(diǎn),顯示最多有一個(gè)額外的列表項(xiàng)。
在運(yùn)行應(yīng)用,主時(shí)間軸開(kāi)始滾動(dòng)時(shí)候,我在終端執(zhí)行了如下命令:
$ adb shell dumpsys gfxinfo com.jv.falcon.pro
在產(chǎn)生的日志中,你會(huì)發(fā)現(xiàn)一個(gè)標(biāo)題為: Profile data in ms. 這一節(jié)包含為每個(gè)窗口所屬應(yīng)用產(chǎn)生的3列表格。 為了使用這些數(shù)據(jù), 簡(jiǎn)單的復(fù)制表格到你喜歡的電子表格軟件中就會(huì)生成一個(gè)堆疊柱狀圖表。下面的圖是我的測(cè)量結(jié)果 (原始表格數(shù)據(jù) 可以在線查看.)
- Draw是消耗在構(gòu)建java顯示列表的時(shí)間。 它顯示出運(yùn)行方法用的時(shí)間諸如View.onDraw(Canvas).
- Process是消耗在Android的2D渲染器執(zhí)行顯示列表的時(shí)間。你的視圖層次越多,要執(zhí)行的繪圖命令就越多。
- Execute是消耗在排列每個(gè)發(fā)送過(guò)來(lái)的幀的順序的時(shí)間.這部分的圖通常是很小的。
注意:使順利在60幀,每幀必須小于16毫秒完成。
關(guān)于Execute:如果執(zhí)行耗費(fèi)了過(guò)長(zhǎng)的時(shí)間,這意味著你是跑在前面的圖形管線。 android在運(yùn)行時(shí)可以有3個(gè)緩沖區(qū).如果你需要另一個(gè)應(yīng)用程序?qū)⒆枞钡狡渲械囊粋€(gè)緩沖區(qū)釋放出來(lái)。兩個(gè)原因會(huì)發(fā)生這種情況。第一,你的應(yīng)用在Dalvik中快速繪制但在GPU顯示列表時(shí)候消耗了大量時(shí)間。第二,你的應(yīng)用程序花了很長(zhǎng)的時(shí)間來(lái)執(zhí)行第幾幀;一旦管線滿了他將無(wú)法趕上,除非動(dòng)畫完成。我們希望Android在未來(lái)版本中改進(jìn)。
該圖顯然證實(shí)了我的懷疑:通常應(yīng)用運(yùn)行良好,不過(guò)有時(shí)候會(huì)運(yùn)行幀率下降。
進(jìn)一步觀察
盡管我們收集的數(shù)據(jù)顯示,應(yīng)用有時(shí)候花費(fèi)太久去渲染,但是這并不是全部的事實(shí)。幀刷新率也能夠被沒(méi)有調(diào)度或者錯(cuò)誤調(diào)度的幀所影響。例如,一個(gè)應(yīng)用總是以少于16ms的時(shí)間來(lái)畫圖,但是有時(shí)候在幀之間展現(xiàn)更長(zhǎng)的任務(wù),有時(shí)他將失去一個(gè)幀。
Systrace 是用于檢查,一個(gè)Falcon Pro 是否在遭受這個(gè)問(wèn)題最簡(jiǎn)單的工具。這個(gè)工具是一個(gè)具有非常低開(kāi)銷的系統(tǒng)分析工具。它的時(shí)域分析相當(dāng)精確,并且給你展示了整個(gè)系統(tǒng)在做什么,包括你的應(yīng)用。
為了讓systrace起作用,進(jìn)入Developer options并且選擇Enable traces。一個(gè)對(duì)話框出現(xiàn),并且讓你選擇你想要分析什么類型的事件。我們只關(guān)心Graphics 和 View。
注意:不要忘記關(guān)掉分析GPU rendering。
#p#
為了使用systrace,打開(kāi)一個(gè)終端,并從Android SDK的tools/systrace下運(yùn)行systrace.py:
默認(rèn)該工具將捕獲5秒鐘的事件。我只是上下滾動(dòng)主時(shí)間軸。跟蹤結(jié)果是一個(gè)獨(dú)立的HTML文件。
建議:為了在systrack中能夠?qū)Ш剑梢允褂肳ASD鍵平移和縮放。W將會(huì)放大鼠標(biāo)光標(biāo)處的內(nèi)容。
一個(gè)systrack文件展示了很多有趣的信息。比如,它表明你是否有一個(gè)進(jìn)程計(jì)劃在CUP。如果你放大到名為10440: m.jv.falcon.pro的最后一行,你能看到應(yīng)用做了些什么。如果你查看performTraversals中的一塊,你能看到應(yīng)用繪制一幀消耗了多長(zhǎng)時(shí)間。
雖然大多數(shù)的performtraversals低于16毫秒的臨界值,但是有些需要更多的時(shí)間,這也證實(shí)了先前獲得的測(cè)量結(jié)果(放大在935 MS標(biāo)記看到這樣一塊。)
更有意思的是,你可以看到應(yīng)用有時(shí)候會(huì)丟失一幀,因?yàn)樗鼪](méi)有安排一個(gè)繪制操作。放大到標(biāo)記為270毫秒的地方,找到deliverInputEvent 塊,消耗25毫秒。這些塊表示應(yīng)用消耗25毫秒來(lái)響應(yīng)用戶觸摸事件。由于應(yīng)用程序是使用ListView,這可能是由于在適配器的一個(gè)問(wèn)題,我們隨后會(huì)回過(guò)頭來(lái)討論。
Systrace十分有用,不僅是它能檢查應(yīng)用消耗過(guò)多的是在繪制上,而且也能幫助我們找到其他的性能瓶頸。盡管它很有用,但是也存在自身的局限性。它只提供了高層次的數(shù)據(jù),我們需要利用其他的工具才能明白它真正發(fā)生了什么。
可視化的透支
繪制性能問(wèn)題可能有很多根本原因,但是其中一個(gè)常見(jiàn)的是透支。透支發(fā)生在應(yīng)用每次向系統(tǒng)請(qǐng)求在其他物體上繪制內(nèi)容。想像一個(gè)最簡(jiǎn)單的應(yīng)用問(wèn)題:一個(gè)白色背景的窗口,在它的上面一個(gè)按鈕。當(dāng)系統(tǒng)繪制按鈕時(shí),要繪制已存在的白色背景上。這就是透支。
透支是不可避免的,但是過(guò)多的透支就會(huì)產(chǎn)生問(wèn)題。設(shè)備具有有限的內(nèi)存帶寬,如果透支導(dǎo)致你的應(yīng)用請(qǐng)求資源超過(guò)了可用帶寬,就是造成性能下降。不同設(shè)備可以明確負(fù)擔(dān)透支的數(shù)量是變化的。
一個(gè)好的經(jīng)驗(yàn)法則是針對(duì)最大透支的2倍;這意味著你可以繪制屏幕一次,再畫上畫兩次,每個(gè)像素總量的3倍。
透支的存在也通常表示其他問(wèn)題:太多的視圖,層次結(jié)構(gòu)復(fù)雜,通脹時(shí)間較長(zhǎng),等
Android提供了三個(gè)工具來(lái)識(shí)別和修復(fù)過(guò)度繪制: Hierarchy Viewer, Tracer for OpenGL 和 Show GPU overdraw。前兩個(gè)可以在ADT或者獨(dú)立的監(jiān)控工具中找到。最后一個(gè)是開(kāi)發(fā)這選項(xiàng)的一部分。
Show GPU overdraw 使用不用的顏色來(lái)繪制屏幕,來(lái)指示過(guò)度繪制在哪里發(fā)生以及程度如何。打開(kāi)此選項(xiàng)然后別忘了關(guān)閉你自己的應(yīng)用 – 未來(lái)的Android版本中將不再需要這樣做。
在看Falcon Pro之前,讓我們看一下設(shè)置Show GPU overdraw選項(xiàng)的頁(yè)面長(zhǎng)什么樣。
如果你記得每種顏色代表的含義,這些結(jié)果就很容易解釋:
- 沒(méi)有顏色意味著沒(méi)有透支。像素只畫了一次。在這個(gè)例子中,你可以看到背景顏色沒(méi)有變化。
- 藍(lán)色 意味著透支1倍。像素繪制了兩次。大片的藍(lán)色還是可以接受的。 (如果整個(gè)窗口是藍(lán)色的,你可以擺脫一層。)
- 綠色 意味著透支2倍。像素繪制了三次。中等大小的綠色區(qū)域是可以接受的但你也應(yīng)該嘗試優(yōu)化,減少他們。
- 淺紅 意味著透支3倍。像素繪制了四次。小范圍內(nèi)可以接受。
- 暗紅 意味著透支4倍。像素繪制了五次或者更多。這是錯(cuò)誤的,要修復(fù)他們。
基于此信息你可以看到設(shè)置是一個(gè)好的應(yīng)用程序,不需要任何額外的工作。有一點(diǎn)紅色在轉(zhuǎn)換部分,但是并不需要過(guò)于糾結(jié)。
透明像素:仔細(xì)看看以前的截圖。每個(gè)圖標(biāo)是藍(lán)色的。你可以看到位圖的透明像素加劇了透支。透明像素必須被GPU處理并且代價(jià)是昂貴的。Android使用層和9-pathches作為最優(yōu)方案去避免繪制透明像素,所有你只用考慮位圖就行。
透支和GPU: 在移動(dòng)設(shè)備上有兩種GPU架構(gòu)。第一個(gè)使用了延遲渲染, 例如:ImaginationTech的SGX系列。 這種架構(gòu)允許GPU檢測(cè)和修復(fù)透支的具體情況 (如果你是混合透明或半透明的像素,它將不起作用)第二結(jié)構(gòu)采用直接繪制,可以在NVIDIA的Tegra GPU的找到。這種體系結(jié)構(gòu)不能優(yōu)化你的透支,這就是為什么我喜歡在Nexus 7試驗(yàn)。兩種架構(gòu)都是各種所長(zhǎng),各有所短,但是具體的內(nèi)容已經(jīng)超出本文范圍。只要知道兩種方式都很好的運(yùn)行。
截圖中有大片的紅色! 然而有趣的是列表的背景是綠色的。這表明該應(yīng)用甚至在繪制正文之前,就有了一個(gè)2倍的過(guò)度繪制。這里我們看到的問(wèn)題很可能跟多重全屏背景有關(guān)。要修復(fù)它通常比較容易。
刪除附加層
為了減少透支,我們必須了解它是怎么來(lái)的。這是比層次視圖、跟蹤OpenGL更有用。層次視圖是ADT(或者監(jiān)聽(tīng)器)的一部分,并可以生成層次視圖快照。特別是調(diào)試布局問(wèn)題,很有幫助,對(duì)性能工作更是得心應(yīng)手。
重要提示:層次視圖只能工作在非安全設(shè)備上,比如工程機(jī)、平板或者模擬器。在某些設(shè)備上使用層次視圖需要在你的應(yīng)用上安裝ViewServer(一個(gè)開(kāi)源庫(kù))。
在ADT(或監(jiān)視器)中打開(kāi) 層次查看視圖 ,然后選擇 Windows 選項(xiàng)卡。斜體高亮的窗口是設(shè)備的前臺(tái)窗口,也就是通常情況下你要查看的那個(gè)。點(diǎn)擊它然后 點(diǎn)擊工具條中的 Load 按鈕 (它看起來(lái)像一個(gè)由藍(lán)方框組成的的樹(shù)形結(jié)構(gòu))。加載這棵樹(shù)可能需要一會(huì)兒所以要有耐心。加載好后,可以看到類似下圖的樣子。
現(xiàn)在層次的視圖已經(jīng)展現(xiàn)在工具中,我們可以查看它就像瀏覽一個(gè)Photoshop文檔那樣。要進(jìn)行查看可以點(diǎn)擊工具條中的第二個(gè)按鈕 – 該按鈕的提示是“捕獲窗口層次[…]”。Adobe Photoshop不是必須的,因?yàn)檫@里生成的文檔也可以由諸如Pixelmator和GIMP之類的工具來(lái)打開(kāi)。我生成的PSD 文件已經(jīng)可以從網(wǎng)上下載。
該P(yáng)hotoshop文檔以每一個(gè)視圖一個(gè)層次的方式展示了該應(yīng)用。每一層都被標(biāo)記為可見(jiàn)或不可見(jiàn),可以通過(guò)View.getVisibility()的返回值來(lái)查看。每一層都以它所屬的視圖來(lái)命名,或者是android:id 或者是類名。我曾經(jīng)嘗試添加分組支持來(lái)重建視圖樹(shù)…我真應(yīng)當(dāng)好好完成該功能。
通過(guò)檢查層級(jí)列表,我們可以快速的確認(rèn)至少一個(gè)過(guò)度繪制的原因:多重全屏背景。第一個(gè)背景是第一層視圖,稱為DecorView。該視圖是Android系統(tǒng)創(chuàng)建的,包含了主題中定義的背景。系統(tǒng)中漸變的默認(rèn)設(shè)置是不可見(jiàn)的,所以可以安全的把它去除掉。
從DecorView向上滾動(dòng),你可以看到一個(gè)包含另一全屏梯度背景的LinearLayout。這是與DecorView完全相同的背景,因此是不必要的。唯一可見(jiàn)的背景,必須保持屬于名為id/tweet_list_container的視圖。
刪除窗口背景:當(dāng)你的應(yīng)用程序啟動(dòng)時(shí),在你的主題中定義的背景是被系統(tǒng)使用創(chuàng)建預(yù)覽窗口的。絕不要把它設(shè)置為null,除非您的應(yīng)用程序是透明的。相反,要把它設(shè)置為你想要的顏色或圖片,或者通過(guò)調(diào)用getWindow().setBackgroundDrawable(null)從onCreate() 中擺脫它。
#p#
進(jìn)一步減少過(guò)度繪制
Photoshop文檔有助于理解應(yīng)用是如何構(gòu)建的,但是用它來(lái)消除小區(qū)域的過(guò)度繪制時(shí)就有些困難了。現(xiàn)在我們必須轉(zhuǎn)向Tracer for OpenGL。打開(kāi)ADT (或監(jiān)視器)中的同名視圖,然后點(diǎn)擊工具條中的箭頭圖標(biāo)。輸入你app的包名和主Activity的名稱,然后選擇一個(gè)目標(biāo)文件并點(diǎn)擊Trace。
建議:獲取OpenGL跟蹤是大任務(wù)并且很耗時(shí)。要使該任務(wù)更輕便更快,請(qǐng)勿勾選所有的Data Collection Ooptions 復(fù)選框。
Activity 名稱:當(dāng)你運(yùn)行一個(gè)應(yīng)用時(shí),logcat會(huì)展示包和Activity的名稱。這就是我怎么知道在Tracer for OpenGL中該敲入些什么的原因。
當(dāng)應(yīng)用啟動(dòng)起來(lái),打開(kāi)前兩個(gè)設(shè)置。
- Collect Framebuffer contents on eglSwapBuffers()
- Collect Framebuffer contents on glDraw*()
第一個(gè)有用的選項(xiàng)能幫助你快速的找到感興趣的幀。第二個(gè)選擇讓我們看到每個(gè)幀由繪圖命令繪制命令。第二個(gè)選項(xiàng)是解決透支問(wèn)題的關(guān)鍵。
這兩個(gè)選項(xiàng)使我開(kāi)始滾動(dòng)主時(shí)間軸。它將消耗很長(zhǎng)時(shí)間去捕捉每一幀(不出意外是30秒)所有我建議你直接下載我的捕獲跟蹤.你可以通過(guò)點(diǎn)擊工具欄上的第一個(gè)按鈕在Tracer for OpenGL打開(kāi)文件。
一旦加載完成。跟蹤顯示你每GL命令發(fā)送到GPU的每個(gè)捕獲的幀。 如果你下載了我的跟蹤文件,跳轉(zhuǎn)到21幀。當(dāng)某一幀被選中你可以看到類似Frame Summary 選項(xiàng)卡情形. 另外,你可以點(diǎn)擊藍(lán)色高亮繪制的命令,在Details 選項(xiàng)卡中查看當(dāng)前幀的狀態(tài)。
組織:GL命令通過(guò)view分組。他們重新創(chuàng)建相同的樹(shù),在你的Hierarchy Viewer或XML布局文件可以查看。這使得了解視圖生成特定的操作很容易。
通過(guò)點(diǎn)擊先后在前三個(gè)繪圖命令,你可以看到在PS已經(jīng)確認(rèn)的問(wèn)題;一個(gè)全屏背景繪制3次。
通過(guò)向下追溯查找,我們可以進(jìn)一步地找到更多有待優(yōu)化的。當(dāng)一個(gè)tweet(列表項(xiàng)目)被繪制的時(shí)候,一個(gè)ImageView控件用來(lái)繪制圖像。控件首先繪制圖像本身的背景:
如果你湊近一點(diǎn)看,你會(huì)發(fā)現(xiàn)背景只是作為圖片的邊框。這意味著在圖像背景中間黑色的部分過(guò)度繪制了。9-patch部分都被圖像覆蓋了。
這個(gè)問(wèn)題的簡(jiǎn)單解決方法是把9-patch中間部分設(shè)置為透明。 Android的 2D渲染器總是把9-patch優(yōu)化為透明。這個(gè)簡(jiǎn)單的改變將會(huì)去掉很多的過(guò)度繪制。
有趣的是, 相同確切的問(wèn)題發(fā)生與內(nèi)聯(lián)元素。頭像小不是個(gè)大問(wèn)題,但內(nèi)聯(lián)元素卻能夠占據(jù)屏幕的絕大部分區(qū)域。解決方法是完全一樣的。
更多的選擇: 我想Android的2D渲染管道,能夠自動(dòng)檢測(cè)和糾正你過(guò)度繪制。我有一些想法但我不能作出任何承諾,就像使用內(nèi)置GPU的優(yōu)化,這只會(huì)與不完全透明圖元。
扁平化(譯注:用“縮減”更直觀)視圖層級(jí)
現(xiàn)在(其實(shí)是大部分時(shí)候)透支是要注意的事情,讓我們回到層級(jí)查看器。通過(guò)檢查層級(jí)樹(shù),我們可以嘗試識(shí)別不必要的視圖。刪除視圖,尤其是視圖組,不僅可以幫助提高幀速率,而且可以減少內(nèi)存消耗和啟動(dòng)時(shí)間等等。
快速瀏覽一下Falcon Pro的視圖層級(jí),足以識(shí)別幾個(gè)只有一個(gè)單獨(dú)子視圖的視圖組。這些視圖組通常是不必要的,很容易去除。至少下面截圖中顯示的節(jié)點(diǎn)中的兩個(gè)應(yīng)該被刪除。
有許多其他的視圖可以從這棵樹(shù)中移除。例如,每個(gè)包含名為 id/listElementBottom的 RelativeLayout的tweet(譯者注:在Twitter上發(fā)布的消息)。此布局包含了作者的名字,他的Twitter地址,這條tweet發(fā)布過(guò)后的時(shí)間,和一個(gè)圖標(biāo)。作者名稱和Twitter地址是兩個(gè)單獨(dú)的 TextView而不是僅用一個(gè),是為了使用不同風(fēng)格。時(shí)間和圖標(biāo)使用一個(gè) TextView 和一個(gè) ImageView,可以使用 TextView的復(fù)合畫板功能合并成一個(gè) TextView。
左邊的滑入式菜單使用了幾組 LinearLayout+TextView+ImageView 來(lái)顯示帶圖標(biāo)的標(biāo)簽。每一組都可以用一個(gè)單獨(dú)的TextView來(lái)替換。
如何擺平你的UI:我在2009年的谷歌I/O上談?wù)摿祟}為激發(fā)你的UI的文章,在其中更詳細(xì)地解釋了這些技術(shù)。
輸入事件處理
還記得當(dāng)我們?cè)诳磗ystrace的時(shí)候發(fā)現(xiàn)觸摸事件響應(yīng)處理有一些延遲嗎?現(xiàn)在就是解決這個(gè)問(wèn)題的時(shí)候啦。traceview就是處置這種問(wèn)題和了解應(yīng)用正在做什么的最好的工具。
Traceview是一個(gè)測(cè)量應(yīng)用的方法調(diào)用所耗時(shí)間的Dalvik分析器。怎樣使用它呢?在ADT或者監(jiān)視器中打開(kāi)DDMS視圖,在Devices選項(xiàng)卡中選擇您的應(yīng)用的進(jìn)程,然后點(diǎn)擊“start method profiling”按鈕(就是一個(gè)紅色圈圈和三個(gè)箭頭的那個(gè)按鈕)。
開(kāi)啟追蹤之后,在主時(shí)間軸上選取開(kāi)始和結(jié)束時(shí)間,再次點(diǎn)擊按鈕來(lái)完成跟蹤。您也可以下載 我的程序調(diào)試信息。結(jié)果如下。
點(diǎn)擊第21行,ViewRootImpl.draw(),該方法調(diào)用時(shí)間將會(huì)高亮。表的最后一行將會(huì)給出這個(gè)方法及其子方法的平均調(diào)用時(shí)間。如果你仔細(xì)看時(shí)間軸上的高亮處,你會(huì)發(fā)現(xiàn)連續(xù)幀之間的差別。
一個(gè)弄清楚這些差別之間是怎么回事的簡(jiǎn)易方法就是在差別開(kāi)始出現(xiàn)的地方逐漸放大,然后點(diǎn)擊其中最大的彩色塊。跟蹤父鏈直到找到你的問(wèn)題所在。在這個(gè)案例中,我跟蹤了Pattern.compileImpl方法的調(diào)用(平均調(diào)用時(shí)間為0.5ms),找到了DBListAdapter.bindView方法.
顯然,應(yīng)用程序?qū)⑾嗤谋磉_(dá)式被一遍又一遍的重復(fù)編譯,每次調(diào)用時(shí)候勢(shì)必在主時(shí)間軸產(chǎn)生一次調(diào)用時(shí)間花費(fèi)。Traceview表明bindview方法的平均調(diào)用時(shí)間為38ms,56%的時(shí)間都花在了HTML文本解析上。這個(gè)花費(fèi)應(yīng)該在后臺(tái)默默的運(yùn)行而不應(yīng)該阻塞UI主線程。當(dāng)然正則表達(dá)式也不應(yīng)該被一次一次的重復(fù)編譯。
試試吧,少年!
最后一個(gè)調(diào)試給大家留作練習(xí)。這是一個(gè)包含兩個(gè)菜單可以向左或向右滑動(dòng)切換的應(yīng)用。但是我在使用openGL調(diào)試工具調(diào)試時(shí)發(fā)現(xiàn)在菜單滑動(dòng)切換的時(shí)候產(chǎn)生了大量的畫圖消耗。下載我的調(diào)試,看看是什么原因造成了這種現(xiàn)象吧(去到第34幀。)
提示:
1、應(yīng)用程序應(yīng)該通過(guò)調(diào)用 View.setLayerType()使用硬件層來(lái)簡(jiǎn)化繪圖。
2、多余的背景也可以通過(guò)9-patches來(lái)巧妙的優(yōu)化。
3、裁剪同樣也是很有用的優(yōu)化方式。
4、通過(guò)設(shè)置ColorFilter傳遞給setLayerType()的畫筆的方式也許可以移除最后的繪圖指令哦。
我們一起學(xué)習(xí)了多種優(yōu)化應(yīng)用的工具。雖然我可以花大量的時(shí)間來(lái)講解選用何種技術(shù)來(lái)解決解決特定問(wèn)題,但是那樣的話這篇文章就會(huì)顯得太臃腫了。android開(kāi)發(fā)者官網(wǎng)上的提供文檔和Google I/O大會(huì)有關(guān)于android的討論(網(wǎng)上有免費(fèi)的幻燈片和視頻)也許能夠幫助你。