我要投稿
  • 您當前的位置:中國教育資源網 -> 技術教程 -> 服務器網絡 -> 服務器教程 -> LinuxBSD教程 -> 教程內容
  • [ 收藏本頁教程 ]
  • Android性能優化案例研究

    教程作者:本站    教程來源:本站整理   教程欄目:LinuxBSD教程    收藏本頁
    摘要: 片頭聲明:1、本片是據Romain Guy劇本編寫Android Performance Case Study衍生的電影,某些部分可能由于個人英語水平有限及理解原因,可能有別于原作者的原意。如有發現,請指正。以利于我們共同學習,共同進步。 ...

    片頭聲明:

    1、本片是據Romain Guy劇本編寫Android Performance Case Study衍生的電影,某些部分可能由于個人英語水平有限及理解原因,可能有別于原作者的原意。如有發現,請指正。以利于我們共同學習,共同進步。

    2、本片是繼Android性能優化案例研究(上)  by孫立出的下版。狗尾續貂,望大家海涵。

    劇情介紹:孫立翻譯的上半部分是如何發現性能問題,我這的下半部分是如何使用工具確定這些問題并給與了部分問題的解決方案。對于上部,就不再這里轉載了,可以直接點擊上面鏈接進行閱讀學習。也可能過幾天會轉載過來

    各位看官,下面就接上部開播:

    移除無用的圖層:為了減少重繪,我們首先必須知道,什么會導致重繪。這也是Hierarchy Viewer和Tracer for OpenGl之前的用處所在。

    Hierarchy Viewer(圖層查看器)是ADT的一部分,可以用于檢查View Hierarchy(視圖層級)的快照。它在解除布局問題時尤其有用,但也可以方便的檢查工作性能。

    【重要:默認情況下Hierarchy Viewer只能工作在非安全模式的設備上,比如工程機、平板或者虛擬機。要在所有手機上使用Hierarchy Viewer,需要添加一個叫ViewServer的開源庫項目到你的應用中。
    https://github.com/romainguy/ViewServer】

    在ADT(或者監視器)中打開Hierarchy Viewer視圖,然后選擇Windows tab。(粗體高亮現實的窗口就是手持終端的foreground設備,一般也就是你要檢測的那個界面)。點擊高亮顯示的條目,然后點擊在工具欄中的Load按鈕。(它看起來想一個藍色方塊樹。)然后耐心等待載入整個樹。當這該視圖樹載入完畢,你將看到如下圖相似的畫面。【譯者:最好使用Monitor,譯者多次使用ADT總是出錯。】


        現在,View Hierarchy已經在工具中載入成功,我們可以將其作為一個圖片文檔導出。只要點擊工具欄中的第二個按鈕(工具提示為:Capture the window layers捕獲窗口圖層)。Adobe Photoshop不是必須的軟件,可以使用與其兼容的工具,比如Pixelmator,GIMP等等。可以下載我生成的PSD文件

        這個圖像文件展示了應用中在一個Layer(圖層)的每一個View。每一個layer(圖層)基View.getVisibility返回的數據,分別被標記為可見或者不可見的。每一個layer(圖層)使用View 可用android:id或者它的類名來命名。我開始添加支持組件來重建視圖樹,我應該完成這個功能。
         通過檢查這一系列圖層,我們可以快速認出至少一個資源的overdraw,多個全屏背景。第一個就是這第一個layer。稱為DecorView。這個視圖被Android生成并包含了在主題中的特殊背景。在應用中這個默認梯度(默認透明度)是不可見的。因此可以安全的將其移除。
    滾動DecorView你可以看見一個LinearLayout包含了另外一個全屏梯度(透明)背景。它與DecorView的背景是完全一樣的,因此,它也是不需要的。唯一可見背景必須保持,它就是命名為id/tweet_list_container的視圖。

    【移除窗口背景:定義在你主題中的背景 被系統用來在啟動的你應用之前作為預顯示窗口。千萬不要將其設置為null除非你的應用是透明的,相反,應該設置一個你認為好的顏色或者圖片,或者在onCreater()方法中調用getWindow().setBackgroundDrawable(null)來將其去掉】。

    進一步的減少overdraw:
    通過圖像文件,我們可以很容易明白應用是怎么生成的。但是它對于移除小區域的overdraw就顯得十分吃力。那我們就需要打開Tracer for OpenGL。在ADT或者Monitor中名字為Tracer for OpenGL的視圖,在工具欄中點擊箭頭那個圖標。輸入你應用的包名和主Activity的名字,然后選擇存放位置(destination File)點擊trace按鈕。

    【建議:OpenGL檢測可能很大并且可以真正減速獲取圖像。 為了讓它更小,獲取圖像更快,不要復選Data Collection Options boxes框。】

    【Activity名字:當你打開應用后,logcat將顯示包名和Activity名字。根據這個你就可以曉得在Tracer for OpenGL中要輸入什么東東了。】



    當應用已經打開并運行,使可用前兩個選項:
    * Collection Framebuffer contents on eglSwapBuffers()
    * Collection Framebuffer contents on glDraw*()
    第一個選項對于快速找到你感興趣的frame十分有用,然而第二個選項則允許我們通過繪制命令查看每個frame生成使用的命令。第二個選項是解決overdraw 問題的關鍵所在。

    開啟這兩個選項之后,我開始滑動主界面的時間軸。它將花費相當長的時間來獲取每一個frame(不出意外的話,需要30秒)。因此我建議你下載我獲取的文件http://goo.gl/yPjB5)。你可以在Tracer for OpenGL中點擊第一個按鈕打開這個文件。

    加載完畢后,視圖展示你每一個發送到GPU的GL命令為一個frame快照。如果你下載我的文件。跳到21Frame處。當一個frame被選中之后,你可以在Frame Sunmmary tab 頁中查看它是什么樣子的。另外,你可以點擊繪制命令,將其藍色高亮,在Details tab頁中查看這個frame的當前狀態。

    【總結:GL 命令被通過View分組。他們重新創建你在HierarchyViewer或者xml Layout文件夾可以看到的樹。這使它很容易就能理解什么View產生了一個什么樣的特定操作。】

    通過連續點擊前三個繪制命令,你可以看出已經在Photoshop中確定的問題,一個全屏的背景被繪制了三次。

    我們通過查看下載的Tracer,可以發現更多可以優化的地方。當一個tweet(listitem)被繪制,一個ImageView被用于繪制頭像(原文是:avatar)。ImageView第一次繪制了一個背景然后繪制頭像(avatar)自身。



    如果你仔細看,你將會發現背景只是作為圖片的一個邊界。這意味著,這意味著在頭像圖片中間的這黑色部分被
    overdraw了。這片9path已經被頭像圖片(avatar)完全覆蓋了。




    一個對于這個問題的簡單修復辦法是使這中間可拉伸的9-patch圖片透明。Android的2d渲染器優化9patches的透明部分。這個簡單的改變將會移除一小部分的overdraw。



    有趣的是,同樣的問題也出現在了內聯媒體(inline media)中。頭像圖片(Avatars)圖片十分小,所以他們overdraw不會導致大的消耗。但是內嵌媒體(inline media)可占據屏幕相當大的一部分區域。問題的修復與上面的方法一致。



    【深度優化:我更希望Android的2d渲染管道有能力自動正確的為你overdraw。我們已經有了些想法,但是我還不能做出任何關于這方面的承諾。正像加入GPU優化,這只能作用于不透明的元素。】

    扁平化視圖(

    Flattening the view hierarchy):


    好的,現在我們已經對overdraw(大部分都是)關心過了,現在讓我們回過頭來再看看Hierarchy viewer。通過檢查圖 像樹,我們能試圖確定不需要的Views。移除Views特別是ViewGroup,這不僅可以提高幀速率,而且還可以減少內存消耗 ,啟動時間等等。 
    快速查看Falcon Pro視圖層級,你可以確定有幾個ViewGroup和一個單獨的子視圖。這些ViewGroup一般都是不需要并且 很容易移除掉。下面展示的圖片中至少最后面的兩個節點是可以移除的。 
     
    也有一些另外的視圖可以從這個樹中移除。比如,每一個tweet都包含了一個命名為listElementBottom的RelativeLayout。這個Layout包含了作者的名字,他的Twitter,從tweet發送出來之后已經過去的時間。名字和handle是 兩個分離的TextView代替了單獨一個TextView加入多種類型不同的spans,時間和icon使用一個TextView和一個 ImageView可以被結合稱一個單獨的TextView,查看TextView's compound drawables    


    左邊的菜單使用了多個LinearLayout+TextView+ImageView的組合來展示標簽和圖標。其實每個可以使用單獨一個TextView就可以代替了。 

    關于“輸入”事件:記不記得當我們查看systrace并且發現,當處理觸摸事件的時候會有些卡頓?現在,是時候來追蹤這個 問題了,traceview是我們去明晰系統正在做什么的最好工具。 

    Traceview是一個記錄應用在調用某個方法花費多少時間的虛擬機分析器。可以在ADT的DDMS視圖或者monitor中啟動他,在Devices tab中選擇你應用進程,然后點擊Start method profiling按鈕。紅色環繞的三個箭頭。 
    在開啟追蹤之后,我來回滑動主時間軸,并且重新點擊按鈕來結束trace。你也可以下載我的追蹤記錄: 
    結果如下圖截屏所示。 
     

    點擊第#21,ViewRootImpl.draw().高亮繪制時間。表格中最后一行給你一個建議關于如何平均花在這個方法和起子方法的時間。如你使用高亮來仔細看這時間軸,你將會注意到在連續frames之間的間隙。 

    一個最簡單找出這些在這些間隙中到底發生了什么方法就是(選擇他們其中一個的開始部分進行放大,然后點擊你能發 現的最大色塊)你追蹤父子鏈(parent chain)直到找到你可以辨識出來的東西。在我的例子中,我追蹤一個花費了平 均時間的0.5ms的叫Patter.compileImpl,所有都指向了DBListAdapter.bindView。 

    顯然每次一旦有新的item被綁定或者滑動主時間軸時,應用都會重新一遍一遍的編譯這相同的正則表達式。Traceview展示了綁定一個View平均花費38ms并且有56%的時間花費在解析HTML文本上。這看起來某些東西可以被可以在后臺實現而不 是阻塞UI線程,正則表達式不應該每次都要重新編譯。 


    接下來看你的了! 
    我留下最后一個trace作為練習。這個應用在兩邊有兩個菜單,可以通過敲擊時間線的左邊或者右邊來顯示。(在顯示這 菜單時GPU overdraws 高亮了過度繪制的部分,我已經使用Tracer for OpenGL來獲取了這個問題的幾幀。下載我的trace然后看看你是否能找到什么導致了overdraw(作者提示go to frame #34)。

    提示就不翻譯了: Hints: the application should use hardware layers by calling View.setLayerType() to simplify drawing. There are also extraneous backgrounds that can be optimized away with clever use of 9-patches. Clipping  could also be very helpful. Finally, maybe a ColorFilter set on a Paint passed to setLayerType() could  help remove the last drawing command.


    我已經展示了多種你可以用于優化你的應用的工具。我已經花費了大量的時間來描述在這些工具的幫助下,使用什么技術去解決已辨別的問題。但是這個文章將會轉到一本書中。檢出文檔這官方文檔( Android developers web site)引用和所有GoogleI/O Android talks.
                                                                                                              ---Romain Guy

    【后語:最好使用Monitor,鄙人在使用ADT的時候老出錯。

    我要投稿   -   廣告合作   -   關于本站   -   友情連接   -   網站地圖   -   聯系我們   -   版權聲明   -   設為首頁   -   加入收藏   -   網站留言
    Copyright © 2009 - 20012 www.obscurenation.com All Rights Reserved.中國教育資源網 版權所有  
     
    彩16app 周宁县 | 东至县 | 松潘县 | 泽州县 | 福州市 | 九龙县 | 通江县 | 新和县 | 屏边 | 建瓯市 | 高青县 | 桐乡市 | 汪清县 | 营口市 | 共和县 | 青州市 | 墨脱县 | 沂南县 | 柏乡县 | 贵溪市 | 镇坪县 | 阜新市 | 五原县 | 富平县 | 陵川县 | 侯马市 | 奈曼旗 | 博客 | 嘉祥县 | 平原县 | 景东 | 探索 | 新巴尔虎右旗 | 惠水县 | 饶河县 | 治多县 | 乌兰浩特市 | 宁武县 | 乐安县 | 石泉县 | 黑山县 | 苏尼特左旗 | 诸暨市 | 庐江县 | 昌乐县 | 镇平县 | 富阳市 | 广东省 | 蓝山县 | 黄平县 | 麟游县 | 日照市 | 南木林县 | 健康 | 栾川县 | 额敏县 | 崇礼县 | 磐安县 | 灌云县 | 宁乡县 | 柳州市 | 永胜县 | 徐闻县 | 惠安县 | 泉州市 | 宝坻区 | 三台县 | 临沂市 | 临泽县 | 利津县 | 城口县 | 扎鲁特旗 | 建平县 | 清流县 | 阿拉善右旗 | 信阳市 | 神农架林区 | 朝阳区 | 安宁市 | 江油市 | 威海市 | 天镇县 | 秦安县 | 惠来县 | 松阳县 | 南木林县 | 峨山 | 普兰县 | 安平县 | 萍乡市 | 安化县 | 玉门市 | 定边县 | 伊宁市 | 吴堡县 | 丹巴县 | 陆河县 | 扶风县 | 溆浦县 | 瑞安市 | 都兰县 | 东安县 | 南开区 | 湘潭市 | 西和县 | 夏河县 | 杭锦后旗 | 奉贤区 | 永城市 | 盐源县 | 梁河县 | 故城县 | 安西县 | 信阳市 | 榆树市 | 怀柔区 | 阳朔县 | 盐山县 | 定边县 | 维西 | 镇康县 | 拜泉县 | 辰溪县 | 革吉县 | 临洮县 | 晋城 | 西藏 | 安多县 | 白银市 | 西乌 | 陆丰市 | 宁德市 | 定州市 | 佛山市 | 鹤峰县 | 满洲里市 | 雷州市 | 县级市 | 肥西县 | 长海县 | 黄龙县 | 新竹县 | 镶黄旗 | 建昌县 | 大兴区 | 手机 | 山东省 | 灵丘县 | 纳雍县 | 增城市 | 永和县 | 黄龙县 | 寿阳县 | 县级市 | 茶陵县 | 根河市 | 漳平市 | 安平县 | 北京市 | 莆田市 | 麻阳 | 白玉县 | 湟中县 | 丰宁 | 文登市 | 永定县 | 通辽市 | 乌什县 | 崇州市 | 陈巴尔虎旗 | 布尔津县 | 上饶县 | 铜川市 | 新源县 | 磴口县 | 霍山县 | 磐安县 | 祁东县 | 改则县 | 伊吾县 | 封开县 | 来凤县 | 延吉市 | 获嘉县 | 桐乡市 | 噶尔县 | 北票市 | 梓潼县 | 河东区 | 宁河县 | 涟水县 | 巴林右旗 | 汉中市 | 丰镇市 | 芜湖县 | 湘潭市 | 广宁县 | 华坪县 | 凌云县 | 东兰县 | 富锦市 | 昌图县 | 花莲市 | 高尔夫 | 金堂县 | 泰兴市 | 巴楚县 | 金湖县 | 禹城市 | 普安县 | 屏东县 | 朝阳县 | 通辽市 | 敖汉旗 | 山西省 | 高密市 | 崇阳县 | 湘乡市 | 通州市 | 武山县 | 香格里拉县 | 福贡县 | 太和县 | 永和县 | 淮滨县 | 固安县 | 深圳市 | 女性 | 静海县 | 岑溪市 | 临夏县 | 达拉特旗 | 临猗县 | 泽州县 | 河北省 | 海兴县 | 镇巴县 | 江永县 | 阳泉市 | 衡水市 | 临桂县 | 铁岭市 | 灵川县 | 宣武区 | 宣恩县 | 旅游 | 邮箱 | 体育 | 喀什市 | 青铜峡市 | 淳化县 |