欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android高級開發(fā)之性能優(yōu)化典范

 更新時間:2016年05月17日 09:58:59   作者:無涯Ⅱ  
本文從電量,視圖,內(nèi)存三個性能方面的知識點給大家介紹android高級開發(fā)之性能優(yōu)化的相關(guān)知識,希望對大家有所幫助

本章介紹android高級開發(fā)中,對于性能方面的處理。主要包括電量,視圖,內(nèi)存三個性能方面的知識點。

1.視圖性能

(1)Overdraw簡介

    Overdraw就是過度繪制,是指在一幀的時間內(nèi)(16.67ms)像素被繪制了多次,理論上一個像素每次只繪制一次是最優(yōu)的,但是由于重疊的布 局導(dǎo)致一些像素會被多次繪制,而每次繪制都會對應(yīng)到CPU的一組繪圖命令和GPU的一些操作,當這個操作耗時超過16.67ms時,就會出現(xiàn)掉幀現(xiàn)象,表現(xiàn)為應(yīng)用卡頓,所以對重疊不可見元素的重復(fù)繪制會產(chǎn)生額外的開銷,需要盡量減少Overdraw的發(fā)生。

(2)Overdraw檢測

    Android提供了測量Overdraw的選項,在開發(fā)者選項-調(diào)試GPU過度繪制(Show GPU Overdraw),打開選項就可以看到當前頁面Overdraw的狀態(tài),就可以觀察屏幕的繪制狀態(tài)。該工具會使用三種不同的顏色繪制屏幕,來指示 overdraw發(fā)生在哪里以及程度如何,其中:

 •沒有顏色: 意味著沒有overdraw。像素只畫了一次。

 •藍色: 意味著overdraw 1倍。像素繪制了兩次。大片的藍色還是可以接受的(若整個窗口是藍色的,可以擺脫一層)。 

•綠色: 意味著overdraw 2倍。像素繪制了三次。中等大小的綠色區(qū)域是可以接受的但你應(yīng)該嘗試優(yōu)化、減少它們。

•淺紅: 意味著overdraw 3倍。像素繪制了四次,小范圍可以接受。

 •暗紅: 意味著overdraw 4倍。像素繪制了五次或者更多。這是錯誤的,要修復(fù)它們。

提高程序在視圖方面的性能, 總的原則就是:盡量避免重疊不可見元素的繪制。

(3)Overdraw改良

1)合理選擇控件容器

    Android提供的Layout控件主要包括 LinearLayout、TableLayout、FrameLayout、RelativeLayout。同一個界面可以使用不同的容器控件來表達,但是各個容器控件描述界面的復(fù)雜度是不一樣的。一般來LinearLayout最易,RelativeLayout較復(fù)雜。 LinearLayout只能用來描述一個方向上連續(xù)排列的控件,而RelativeLayout幾乎可以用于描述任意復(fù)雜度的界面。。綜上所述: LinearLayout易用,效率高,表達能力有限。RelativeLayout復(fù)雜,表達能力強,效率低。從減少overdraw的角度來看,LinearLayout會增加控件數(shù)的層級,自然是RelativeLayout 更優(yōu),但是當某一界面在使用LinearLayout并不會比RelativeLayout帶來更多的控件數(shù)和控件層級時,LinearLayout則是首選。

2)去掉window的默認背景

   當使用Android自帶的一些主題時,window會被默認添加一個純色的背景,這個背景是被DecorView持有的。當自定義布局時又添加了一張背景圖或者設(shè)置背景色,那么DecorView的background此時是無用的,但是它會產(chǎn)生一次Overdraw,帶來繪制性能損耗。去掉window的背景可以在onCreate()中setContentView()之后調(diào)用 getWindow().setBackgroundDrawable(null);或者在theme中添加 android:windowbackground="null"。

3)去掉其他不必要的背景

    父容器若已經(jīng)有了背景,可不設(shè)置對應(yīng)子控件的背景,及大的布局背景已經(jīng)設(shè)置,應(yīng)避免設(shè)置局部重復(fù)的背景。

4)自定義View處理

    對于自定義的view視圖,可以通過canvas.clipRect()來幫助系統(tǒng)識別那些可見的區(qū)域。這個方法可以指定一塊矩形區(qū)域,只有在這個區(qū)域內(nèi)才會被繪制,其他的區(qū)域會被忽視。這個API可以很好的幫助那些有多組重疊組件的自定義View來控制顯示的區(qū)域。同時clipRect方法還可以幫助節(jié)約CPU與GPU資源,在clipRect區(qū)域之外的繪制指令都不會被執(zhí)行,那些部分內(nèi)容在矩形區(qū)域內(nèi)的組件,仍然會得到繪制。除了clipRect方法之外,我們還可以使用canvas.quickreject()來判斷是否沒和某個矩形相交,從而跳過那些非矩形區(qū)域內(nèi)的繪制操作。

5)ViewStub高效占位符

    當遇到這樣的情況,運行時動態(tài)根據(jù)條件來決定顯示哪個View或布局。常用的做法是把View都寫在上面,先把它們的可見性都設(shè)為 View.GONE,然后在代碼中動態(tài)的更改它的可見性。這種模式的缺點是耗費資源。雖然把View 的初始View.GONE但是在Inflate布局的時候View仍然會被Inflate,程序運行時仍然會創(chuàng)建對象,會被實例化,會被設(shè)置屬性,會耗費內(nèi)存等資源。

   推薦的做法是使用android.view.ViewStub,ViewStub是一個輕量級的View,它一個看不見的,不占布局位置,占用資源非常小的控件。可以為ViewStub指定一個布局,在Inflate布局的時候,只有ViewStub會被初始化,然后當ViewStub被設(shè)置為可見的時候,或是調(diào)用了ViewStub.inflate()的時候,ViewStub所向的布局就會被Inflate和實例化,然后ViewStub的布局屬性都會傳給它所指向的布局。這樣,就可以使用ViewStub來方便的在運行時,要還是不要顯示某個布局。

6)善用draw9patch

    給ImageView加一個邊框,通常在ImageView后面設(shè)置一張背景圖,露出邊框便完美解決問題,此時這個 ImageView,設(shè)置了兩層drawable,兩層drawable的重疊區(qū)域去繪制了兩次,導(dǎo)致 overdraw。優(yōu)化方案: 將背景drawable制作成draw9patch,并且將和前景重疊的部分設(shè)置為透明。由于Android的2D渲染器會優(yōu)化draw9patch中的透明區(qū)域,從而優(yōu)化了這次overdraw。

7)Merge 

    使用Merge標簽來做容器控件。第一種子視圖不需要指定任何針對父視圖的布局屬性,就是說父容器僅僅是個容器,子視圖只需要直接添加到父視圖上用于顯示 就 行。另外一種是假如需要在LinearLayout里面嵌入一個布局 (或者視圖),而恰恰這個布局(或者視圖)的根節(jié)點也是LinearLayout,這樣就多了一層沒有用的嵌套,無疑這樣只會拖慢程序速度。而這個時候如 果我們使用merge根標簽就可以避免那樣的問題。

2.內(nèi)存性能

(1)內(nèi)存分配與回收

    每一個進程的Dalvik Heap都反映了使用內(nèi)存的占用范圍。這就是通常邏輯意義上提到的Dalvik Heap Size,它可以隨著需要進行增長,但是增長行為會有一個系統(tǒng)為它設(shè)定上限。

    邏輯上講的Heap Size和實際物理意義上使用的內(nèi)存大小是不對等的,Proportional Set Size(PSS)記錄了應(yīng)用程序自身占用以及與其他進程進行共享的內(nèi)存。

    Android 系統(tǒng)并不會對Heap中空閑內(nèi)存區(qū)域做碎片整理。系統(tǒng)僅僅會在新的內(nèi)存分配之前判斷Heap的尾端剩余空間是否足夠,如果空間不夠會觸發(fā)GC操作,從而騰 出更多空閑的內(nèi)存空間。在Android的高級系統(tǒng)版本里面針對Heap空間有一個Generational Heap Memory的模型,最近分配的對象會存放在Young Generation區(qū)域。當這個對象在該區(qū)域停留的時間達到一定程度,它會被移動到Old Generation,最后累積一定時間再移動到Permanent Generation區(qū)域。系統(tǒng)會根據(jù)內(nèi)存中不同的內(nèi)存數(shù)據(jù)類型分別執(zhí)行不同的GC操作。例如,剛分配到Y(jié)oung Generation區(qū)域的對象通常更容易被銷毀回收,同時在Young Generation區(qū)域的GC操作速度會比Old Generation區(qū)域的GC操作速度更快(如圖1所示)。

 

圖1  根據(jù)不同內(nèi)存數(shù)據(jù)類型執(zhí)行不同GC操作

    每一個Generation的內(nèi)存區(qū)域都有固定的大小。隨著新的對象陸續(xù)被分配到此區(qū)域,當對象總的大小臨近這一級別內(nèi)存區(qū)域的閥值時,會觸發(fā)GC操作,以便騰出空間來存放其他新的對象(如圖2所示)。

 

圖2  對象值臨近閥值觸發(fā)GC操作

    通常情況下,GC發(fā)生的時候,所有的線程都是會被暫停的。執(zhí)行GC所占用的時間和它發(fā)生在哪一個Generation也有關(guān)系,Young Generation中的每次GC操作時間是最短的,Old Generation其次,Permanent Generation最長。執(zhí)行時間的長短也和當前Generation中的對象數(shù)量有關(guān),遍歷樹結(jié)構(gòu)查找20000個對象比起遍歷50個對象自然是要慢 很多的。

(2)內(nèi)存測試插件

1)LeakCanary簡介

    LeakCanary是一個用于檢測內(nèi)存泄漏的工具,可以用于Java和Android,是由著名開源組織Square貢獻。

2)LeakCanary工作原理

 •RefWatcher.watch()創(chuàng)建一個KeyedWeakReference到北監(jiān)控的對象。

 •接下來,在后臺線程中檢測這個引用是否被清除,如果沒有將會觸發(fā)GC。

•如果引用仍然沒有清除,將heap內(nèi)存dump到一個.hprof的文件存放到手機系統(tǒng)里。

 •HeapAnalyzerService在另外一個獨立的進程中啟動,使用HeapAnalyzer解析heap內(nèi)存通過HAHA這個項目

 •HeapAnalyzer計算出到GC ROOTs的最短強引用路徑?jīng)Q定是否發(fā)生Leak,然后建立導(dǎo)致泄漏的引用鏈。 結(jié)果被回傳到應(yīng)用程序進程的DisplayLeakService中,然后顯示一個泄漏的通知。

(3)內(nèi)存優(yōu)化

1)謹慎使用large heap

    Android設(shè)備根據(jù)硬件與軟件的設(shè)置差異而存在不同大小的內(nèi)存空間,他們?yōu)閼?yīng)用程序設(shè)置了不同大小的Heap限制閾值。設(shè)計時可以通過調(diào)用getMemoryClass()來獲取應(yīng)用的可用Heap大小。在一些特殊的情景下,你可以通過在manifest的application標簽下添加 largeHeap=true的屬性來為應(yīng)用聲明一個更大的heap空間。然后,你可以通過getLargeMemoryClass()來獲取到這個更大的heap size閾值。

    然而,聲明得到更大Heap閾值的本意是為了一小部分會消耗大量RAM的應(yīng)用(例如一個大圖片的編輯應(yīng)用)。不要輕易的因為你需要使用更多的內(nèi)存而去請求一個大的Heap Size。只有當你清楚的知道哪里會使用大量的內(nèi)存并且知道為什么這些內(nèi)存必須被保留時才去使用large heap。因此請謹慎使用large heap屬性。使用額外的內(nèi)存空間會影響系統(tǒng)整體的用戶體驗,并且會使得每次gc的運行時間更長。

2)綜合考慮設(shè)備內(nèi)存閾值與其他因素設(shè)計合適的緩存大小

    例如,在設(shè)計ListView或者GridView的Bitmap LRU緩存的時候,需要考慮的點有:

 •應(yīng)用程序剩下了多少可用的內(nèi)存空間?

 •有多少圖片會被一次呈現(xiàn)到屏幕上?有多少圖片需要事先緩存好以便快速滑動時能夠立即顯示到屏幕?

 •設(shè)備的屏幕大小與密度是多少? 一個xhdpi的設(shè)備會比hdpi需要一個更大的Cache來hold住同樣數(shù)量的圖片。

 •不同的頁面針對Bitmap的設(shè)計的尺寸與配置是什么,大概會花費多少內(nèi)存?

 •頁面圖片被訪問的頻率?是否存在其中的一部分比其他的圖片具有更高的訪問頻繁?如果是,也許你想要保存那些最常訪問的到內(nèi)存中,或者為不同組別的位圖(按訪問頻率分組)設(shè)置多個LruCache容器。

3)資源文件需要選擇合適的文件夾進行存放

   hdpi/xhdpi/xxhdpi等等不同dpi的文件夾下的圖片在不同的設(shè)備上會經(jīng)過scale的處理。例如我們只在hdpi的目錄下放置了一 張100100的圖片,那么根據(jù)換算關(guān)系,xxhdpi的手機去引用那張圖片就會被拉伸到200200。需要注意到在這種情況下,內(nèi)存占用是會顯著提高 的。對于不希望被拉伸的圖片,需要放到assets或者nodpi的目錄下。

4)Try catch某些大內(nèi)存分配的操作

    在某些情況下,我們需要事先評估那些可能發(fā)生OOM的代碼,對于這些可能發(fā)生OOM的代碼,加入catch機制,可以考慮在catch里面嘗試一次降級的內(nèi)存分配操作。例如decode bitmap的時候,catch到OOM,可以嘗試把采樣比例再增加一倍之后,再次嘗試decode。

5)謹慎使用static對象

    因為static的生命周期過長,和應(yīng)用的進程保持一致,使用不當很可能導(dǎo)致對象泄漏,在Android中應(yīng)該謹慎使用static對象。

6)特別留意單例對象中不合理的持有

    雖然單例模式簡單實用,提供了很多便利性,但是因為單例的生命周期和應(yīng)用保持一致,使用不合理很容易出現(xiàn)持有對象的泄漏。

7)珍惜Services資源

    應(yīng)用需要在后臺使用service,除非它被觸發(fā)并執(zhí)行一個任務(wù),否則其他時候Service都應(yīng)該是停止狀態(tài)。另外需要注意當這個service 完成任務(wù)之后因為停止service失敗而引起的內(nèi)存泄漏。 當你啟動一個Service,系統(tǒng)會傾向為了保留這個Service而一直保留Service所在的進程。這使得進程的運行代價很高,因為系統(tǒng)沒有辦法把 Service所占用的RAM空間騰出來讓給其他組件,另外Service還不能被Paged out。這減少了系統(tǒng)能夠存放到LRU緩存當中的進程數(shù)量,它會影響應(yīng)用之間的切換效率,甚至?xí)?dǎo)致系統(tǒng)內(nèi)存使用不穩(wěn)定,從而無法繼續(xù)保持住所有目前正在運行的service。 建議使用IntentService,它會在處理完交代給它的任務(wù)之后盡快結(jié)束自己。

8)使用ProGuard來剔除不需要的代碼

   ProGuard能夠通過移除不需要的代碼,重命名類,域與方法等等對代碼進行壓縮,優(yōu)化與混淆。使用ProGuard可以使得你的代碼更加緊湊,這樣能夠減少mapping代碼所需要的內(nèi)存空間。

9)使用更加輕量的數(shù)據(jù)結(jié)構(gòu)

   考慮使用ArrayMap/SparseArray而不是HashMap等傳統(tǒng)數(shù)據(jù)結(jié)構(gòu)。

   HashMap的容器,相比起 Android專門為移動操作系統(tǒng)編寫的ArrayMap容器,在大多數(shù)情況下,都顯示效率低下,更占內(nèi)存。通常的HashMap的實現(xiàn)方式更加消耗內(nèi)存,因為它需要一個額外的實例對象來記錄Mapping操作。另外,SparseArray更加高效,在于他們避免了對key與value的自動裝箱 (autoboxing),并且避免了裝箱后的解箱。

10)避免在Android里面使用Enum

  Android 官方培訓(xùn)課程提到過“Enums often require more than twice as much memory as static constants. You should strictly avoid using enums on Android.”,具體原理請參考《Android性能優(yōu)化典范(三)》,所以請避免在Android里面使用到枚舉。

11)減小Bitmap對象的內(nèi)存占用

    Bitmap是一個極容易消耗內(nèi)存的大胖子,減小創(chuàng)建出來的Bitmap的內(nèi)存占用可謂是重中之重,通常來說有以下2個措施:
 •inSampleSize:縮放比例,在把圖片載入內(nèi)存之前,我們需要先計算出一個合適的縮放比例,避免不必要的大圖載入。
 •decode format:解碼格式,選擇ARGB_8888/RBG_565/ARGB_4444/ALPHA_8,存在很大差異。

12)使用更小的圖片

    在涉及給到資源圖片時,我們需要特別留意這張圖片是否存在可以壓縮的空間,是否可以使用更小的圖片。盡量使用更小的圖片不僅可以減少內(nèi)存的使用,還能避免出現(xiàn)大量的InflationException。假設(shè)有一張很大的圖片被XML文件直接引用,很有可能在初始化視圖時會因為內(nèi)存不足而發(fā)生InflationException,這個問題的根本原因其實是發(fā)生了OOM。

13)內(nèi)存對象的重復(fù)利用

  大多數(shù)對象的復(fù)用,最終實施的方案都是利用對象池技術(shù),要么是在編寫代碼時顯式地在程序里創(chuàng)建對象池,然后處理好復(fù)用的實現(xiàn)邏輯。要么就是利用系統(tǒng)框架既有的某些復(fù)用特性,減少對象的重復(fù)創(chuàng)建,從而降低內(nèi)存的分配與回收。

14)復(fù)用系統(tǒng)自帶的資源

    Android 系統(tǒng)本身內(nèi)置了很多的資源,比如字符串、顏色、圖片、動畫、樣式以及簡單布局等,這些資源都可以在應(yīng)用程序中直接引用。這樣做不僅能減少應(yīng)用程序的自身負重,減小APK的大小,還可以在一定程度上減少內(nèi)存的開銷,復(fù)用性更好。但是也有必要留意Android系統(tǒng)的版本差異性,對那些不同系統(tǒng)版本上表現(xiàn)存在很大差異、不符合需求的情況,還是需要應(yīng)用程序自身內(nèi)置進去。

15)注意Cursor對象是否及時關(guān)閉

    在程序中我們經(jīng)常會進行查詢數(shù)據(jù)庫的操作,但時常會存在不小心使用Cursor之后沒有及時關(guān)閉的情況。這些Cursor的泄露,反復(fù)多次出現(xiàn)的話會對內(nèi)存管理產(chǎn)生很大的負面影響,我們需要謹記對Cursor對象的及時關(guān)閉。

16)避免在onDraw方法里面執(zhí)行對象的創(chuàng)建

   類似onDraw等頻繁調(diào)用的方法,一定需要注意避免在這里做創(chuàng)建對象的操作,因為他會迅速增加內(nèi)存的使用,而且很容易引起頻繁的gc,甚至是內(nèi)存抖動。

17)StringBuilder

    在有些時候,代碼中會需要使用到大量的字符串拼接的操作,這種時候有必要考慮使用StringBuilder來替代頻繁的“+”。

18)注意Activity的泄漏

 通常來說,Activity的泄漏是內(nèi)存泄漏里面最嚴重的問題,它占用的內(nèi)存多,影響面廣,需要特別注意以下兩種情況導(dǎo)致的Activity泄漏:

 •內(nèi)部類引用導(dǎo)致Activity的泄露

   最典型的場景是Handler導(dǎo)致的Activity泄漏,如果Handler中有延遲的任務(wù)或者是等待執(zhí)行的任務(wù)隊列過長,都有可能因為Handler繼 續(xù)執(zhí)行而導(dǎo)致Activity發(fā)生泄漏。此時的引用關(guān)系鏈是Looper -> MessageQueue -> Message -> Handler -> Activity。為了解決這個問題,可以在UI退出之前,執(zhí)行remove Handler消息隊列中的消息與runnable對象。或者是使用Static + WeakReference的方式來達到斷開Handler與Activity之間存在引用關(guān)系的目的。

•Activity Context被傳遞到其他實例中,這可能導(dǎo)致自身被引用而發(fā)生泄漏。

    內(nèi)部類引起的泄漏不僅僅會發(fā)生在Activity上,其他任何內(nèi)部類出現(xiàn)的地方,都需要特別留意!可以考慮盡量使用static類型的內(nèi)部類,同時使用WeakReference的機制來避免因為互相引用而出現(xiàn)的泄露。

19)考慮使用Application Context而不是Activity Context

    對于大部分非必須使用Activity Context的情況(Dialog的Context就必須是Activity Context),都可以考慮使用Application Context而不是Activity的Context,這樣可以避免不經(jīng)意的Activity泄露。

(3)電量優(yōu)化

    電量其實是目前手持設(shè)備最寶貴的資源之一,大多數(shù)設(shè)備都需要不斷的充電來維持繼續(xù)使用。不幸的是,對于開發(fā)者來說,電量優(yōu)化是他們最后才會考慮的的事情。但是可以確定的是,千萬不能讓你的應(yīng)用成為消耗電量的大戶。

有下面一些措施能夠顯著減少電量的消耗:

 •我們應(yīng)該盡量減少喚醒屏幕的次數(shù)與持續(xù)的時間,使用WakeLock來處理喚醒的問題,能夠正確執(zhí)行喚醒操作并根據(jù)設(shè)定及時關(guān)閉操作進入睡眠狀態(tài)。
 •某些非必須馬上執(zhí)行的操作,例如上傳歌曲,圖片處理等,可以等到設(shè)備處于充電狀態(tài)或者電量充足的時候才進行。
 •觸發(fā)網(wǎng)絡(luò)請求的操作,每次都會保持無線信號持續(xù)一段時間,我們可以把零散的網(wǎng)絡(luò)請求打包進行一次操作,避免過多的無線信號引起的電量消耗。關(guān)于網(wǎng)絡(luò)請求引起無線信號的電量消耗。

1)消耗電量的幾個主要原因、功能

 •大數(shù)據(jù)量的網(wǎng)絡(luò)傳輸(網(wǎng)絡(luò))

 •不停的網(wǎng)絡(luò)切換(網(wǎng)絡(luò))

 •解析大量的數(shù)據(jù)(CPU)

2)關(guān)于網(wǎng)絡(luò)方面的優(yōu)化

 •網(wǎng)絡(luò)請求之前,檢查網(wǎng)絡(luò)連接。沒有網(wǎng)絡(luò)連接不進行請求

 •判斷網(wǎng)絡(luò)類型,針對特定的數(shù)據(jù)在特定的網(wǎng)絡(luò)下請求。例如:大量數(shù)據(jù)傳輸?shù)臅r候,在wifi下請求。wifi下下載數(shù)據(jù)耗電量只有2、3、4G的1/3.

 •使用效率高的解析工具。根據(jù)具體業(yè)務(wù)數(shù)據(jù)量的大小,選擇合適的解析工具。例如android上面的協(xié)議解析一般推薦json。

 •使用GZIP壓縮方式下載數(shù)據(jù),能減少網(wǎng)絡(luò)流量,縮短下載時間

•合理使用緩存,避免重復(fù)操作

 •使用推送,代替循環(huán)請求

 •觸發(fā)網(wǎng)絡(luò)請求的操作,每次都會保持無線信號持續(xù)一段時間,我們可以把零散的網(wǎng)絡(luò)請求打包進行一次操作,避免過多的無線信號引起的電量消耗。

 •是JobScheduler API所做的事情。它會根據(jù)當前的情況與任務(wù),組合出理想的喚醒時間,例如等到正在充電或者連接到WiFi的時候,或者集中任務(wù)一起執(zhí)行。我們可以通過這個API實現(xiàn)很多免費的調(diào)度算法。

3)電量優(yōu)化策略

 •檢查全部喚醒鎖, 是否存在冗余或者無用的位置.

 •集中相關(guān)的數(shù)據(jù)請求, 統(tǒng)一發(fā)送; 精簡數(shù)據(jù), 減少無用數(shù)據(jù)的傳輸.

 •分析和統(tǒng)計等非重要操作, 可以在電量充足或連接WIFI時進行, 參考JobScheduler.

 •精簡冗余的服務(wù)(Service), 避免長時間執(zhí)行耗電操作.

 •注意定位信息的獲取, 使用后及時關(guān)閉.

以上所述是小編給大家介紹的Android高級開發(fā)之性能優(yōu)化典范的相關(guān)知識,希望對大家有所幫在,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!

相關(guān)文章

最新評論