兩年前,我發(fā)表了一篇名為Android性能案例研究的文章,幫助Andriod開發(fā)者理解哪些工具和技術(shù)可被用于識別、跟蹤并解決性能問題。
這篇文章專注于一個推特客戶端設計Falcon Pro,它是由Joaquim Vergès開發(fā)的。Joaquim非常好,他允許我在我的文章中使用他的應用程序,并迅速解決我發(fā)現(xiàn)的所有問題。一切進展都非常順利,直到Joaquim開始從頭開始編寫Falcon Pro 3。前不久Joaquim發(fā)行自己的新應用,他聯(lián)系到我,因為他需要我?guī)椭鉀Q影響滾動的性能問題(再一次,我沒有訪問源代碼)。
Joaquim使用了所有合適的工具,并能迅速排除那些沒有產(chǎn)生問題的方面。例如,他發(fā)現(xiàn)過度拉大不是一個產(chǎn)生問題的原因。然而,他能夠縮小問題到ViewPager的使用方面。他發(fā)給我下面的截圖:
http://wiki.jikexueyuan.com/project/android-weekly/images/issue-146/9.1.png" alt="alt text" />
Joaquim使用系統(tǒng)屏幕上的GPU分析工具來檢測幀率下降。左邊的屏幕截圖顯示了沒有ViewPager的滾動時間線性能,右邊的截圖顯示了帶有一個 ViewPager的性能(他使用2014 Moto X捕捉到這一數(shù)據(jù))。產(chǎn)生問題的根本原因似乎很明顯。
我的第一個想法是看看ViewPager是否不明原因地濫用硬件層。觀察到的性能問題可能是由于列表滾動的每一幀引起硬件層更新造成的。系統(tǒng)的硬件層更新調(diào)試工具沒有發(fā)現(xiàn)任何問題。我仔細檢查了HierarchyViewer,令人欣慰的是ViewPager的行為是正確的。
然后我準備使用另一個強大的、很少用的,叫做Tracer for OpenGL的工具。我以前的文章講述了如何使用這款工具的更多細節(jié)。你所需要知道的是,這個工具會收集所有的UI工具包發(fā)送到GPU的繪圖指令。
Android 4.3及以上版本:不幸的是,當我們在Android 4.3以上版本中引入繪圖指令的重排和合并后,Tracer變得更加難以使用。這是一個非常有用的優(yōu)化,但它可以防止Tracer獲取分組視圖指令。你可以通過使用以下指令禁用顯示列表的優(yōu)化來恢復以前版本中繪圖指令的行為:
讀取OpenGL追蹤:圖中藍色的指令是GL繪制像素到屏幕上。所有其他指令用于傳輸數(shù)據(jù)或設置狀態(tài),很容易被忽視。每次你點擊一個藍色的指令,Tracer將更新Details選項卡并在你點擊執(zhí)行指令后顯示你當前的渲染目標的內(nèi)容。你可以通過一個接一個地點擊每一個藍色的指令重建一幀。這就是我如何使用Tracer分析性能問題的過程。通過查看每一幀是如何渲染的,可以獲得應用程序正在執(zhí)行情況的很多見解。
在我仔細閱讀了追蹤收集到的Falcon Pro I滾動過程之后,我很驚訝地看到一系列塊指令SaveLayer/ComposeLayer(點擊圖片看大圖):
http://wiki.jikexueyuan.com/project/android-weekly/images/issue-146/9.2.png" alt="alt text" />
這些塊表明了臨時硬件層的創(chuàng)建和組成。這些臨時層是由Canvas.saveLayer()的不同變體創(chuàng)建的。當滿足特定條件時,UI工具包使用 Canvas.saveLayer() 繪制alpha < 1(見View.setAlpha())的Views:
Chet和我在一些介紹中解釋了“為什么你應該慎重的使用alpha”。每次UI工具包必須使用臨時層時,繪圖指令會被發(fā)送到不同的渲染目標,以及切換渲染目標操作對GPU來說消耗很大。GPU使用平鋪/遞延架構(gòu)(ImaginationTech的SGX、Qualcomm的Adreno等等)明顯地被這種行為所傷害。例如Nvidia的直接渲染架構(gòu)會適用的好一些。由于Joaquim 和我研究的Moto X 2014設備使用了Qualcomm Adreno GPU,使用多個臨時的硬件層是出現(xiàn)我們所面臨性能問題的最可能的根本原因。
因此,主要問題變成:是什么創(chuàng)造了這些臨時層?Tracer 給我們提供了答案。如果你看一下Tracer的截圖就可以發(fā)現(xiàn),OpenGL操作的SaveLayer 組中唯一的繪圖指令渲染的似乎是一個小渲染目標中的圓(使用工具放大的結(jié)果)。現(xiàn)在,讓我們來看看應用程序的截圖:
http://wiki.jikexueyuan.com/project/android-weekly/images/issue-146/9.3.png" alt="alt text" />
你看到頂部這些小圓圈了嗎?那是一個ViewPager 指針,用于顯示用戶的位置。Joaquim使用了第三方程序庫(我不記得是哪一個了)來繪制這些指針。有趣的是這個程序庫如何繪制了該指針:當前頁是一個白色的圓圈表示,在其他頁面似乎是一個灰色的圓圈。我說“這似乎是一個灰色的”,是因為這些圓圈其實是半透明的白色圓圈。這個程序庫為每一個圓圈使用View(這本身就是浪費),并調(diào)用setAlpha()改變它們的顏色。
這里有解決這個問題的幾種解決方案:
最簡單的解決方法是第二個,但是它僅適用于API16以上。如果你必須支持老版本的Android,那么使用其他兩種解決方案。我相信Joaquim會拋棄第三方程序庫,改為使用他自己的指針。
我希望這篇文章能明確指出那些似乎是無辜和無害操作所引起的性能問題。所以請記?。翰灰黾僭O,而是要采取措施!