前述
一個好的app除了有吸引人的功能, 美麗的交互之外,性能也至關重要,作為一個技術人員,在這里當然只能講技術了
一般app性能優(yōu)化主要從一下幾個方面入手,
- 啟動速度優(yōu)化
- app卡頓,流暢度優(yōu)化
- 內存優(yōu)化
- 代碼優(yōu)化
- apk瘦身優(yōu)化
- 電量優(yōu)化
- 穩(wěn)定性優(yōu)化
啟動速度優(yōu)化
對于app啟動的優(yōu)化,一般啟動的時候設置一個主題/圖片防止白屏或者延遲打開
<style name="appTheme" parent="Theme.AppCompat.Light.NoActionBar">
<item name="android:windowBackground">@drawable/splash</item>
<item name="android:windowFullscreen">true</item>
</style>
如果啟動頁面不是一張圖片,而且通過布局顯示可以利用Splash加載部分圖片先顯示出來
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!--白色矩形 作為背景色-->
<item>
<shape android:shape="rectangle">
<solid android:color="@android:color/white" />
</shape>
</item>
<!--單獨的slogan圖片 并且設置下間距-->
<item android:bottom="0dp">
<!--位置設置成靠下-->
<bitmap
android:gravity="bottom"
android:src="@mipmap/bg_load_button" />
</item>
</layer-list>
在5.0后,增加了一個windowDrawsSystemBarBackgrounds屬性媳叨,用來標志此窗口是否負責繪制系統(tǒng)欄背景,我們把它設成false
十兢,這樣當它繪制windowBackground
的時候餐济,就會在NavigationBar
之上耘擂。
因為這個屬性是5.0以后才有的,所以需要新建values-v21
文件夾絮姆,以便5.0以上的機器使用v21的Splash主題醉冤。
針對啟動速度慢,需要盡可能減少Applicatio和啟動頁面的onCreate中所要做的事情,比如一些不重要的SDK延遲或者異步加載篙悯;部分第三方的初始化(如極光的初始化就很耗時)可以使用到的類異步加載蚁阳;如果對于設備5.0以下,還要考慮multidex的優(yōu)化.提高啟動頁面響應速度,一般點擊app進入到首頁不能超過3秒,如果超過3秒就應該要做處理了.
對于如何檢測方法耗時,除了打印log,adb命令可以使用TraceView去看,后面我們會講到
卡頓優(yōu)化
談到UI流暢度,一般就是不要在主進程去做耗時的操作鸽照,提升UI的繪制速度,下面幾點需要注意
不要在主線程進行網絡訪問/大文件的IO操作
繪制UI時螺捐,盡量減少繪制UI層次;減少不必要的view嵌套矮燎,減少重復繪制,可以用Hierarchy Viewer工具來檢測定血,后面會詳細講;
當我們的布局是用的FrameLayout的時候诞外,我們可以把它改成merge,可以避免自己的幀布局和系統(tǒng)的ContentFrameLayout幀布局重疊造成重復計算(measure和layout)
參考鏈接
提高顯示速度,使用ViewStub:當加載的時候才會占用澜沟。不加載的時候就是隱藏的,僅僅占用位置浅乔。
在view層級相同的情況下倔喂,盡量使用 LinerLayout而不是RelativeLayout;因為RelativeLayout在測量的時候會測量二次靖苇,而LinerLayout測量一次席噩,可以看下它們的源碼;
刪除控件中無用的屬性;
布局復用.比如listView 布局復用
盡量避免過度繪制(overdraw)比如:背景經常容易造成過度繪制贤壁。由于我們布局設置了背景悼枢,同時用到的MaterialDesign的主題會默認給一個背景。這時應該把主題添加的背景去掉脾拆;還有移除 XML 中非必須的背景
自定義View優(yōu)化馒索。使用 canvas.clipRect()來幫助系統(tǒng)識別那些可見的區(qū)域,只有在這個區(qū)域內才會被繪制名船。也是避免過度繪制.
合理的刷新機制绰上,盡量減少刷新次數(shù),盡量避免后臺有高的 CPU 線程運行渠驼,縮小刷新區(qū)域蜈块。
采用開銷較低的布局:例如,您可能會發(fā)現(xiàn),TableLayout 作為具有許多位置依賴項的更復雜的布局百揭,可以提供相同的功能爽哎。在 Android 的 N 版本中,ConstraintLayout 類提供了與 RelativeLayout 類似的功能器一,但開銷要低得多课锌。
性能問題并不容易復現(xiàn),也不好定位祈秕,下面介紹幾個非常有用的工具分析卡頓
-
1.Profile GPU Rendering
在手機開發(fā)者模式下渺贤,有一個卡頓檢測工具叫做:Profile GPU Rendering
image.png
下面用一張圖來解析各個顏色對應的意思(特別需要注意的我紅色框了出來)
image.png
總之,保持動畫流暢的關鍵就在于讓這些垂直的柱狀條盡可能地保持在綠線下面,任何時候超過綠線,你就有可能丟失一幀的內容. -
2.Debug GPU overDraw過度繪制檢測
在手機開發(fā)者模式下请毛,有一個過度繪制檢測工具叫做:Debug GPU overDraw,看圖:
image.png
各個顏色代表的意義
Android 將按如下方式為界面元素著色癣亚,以確定過度繪制的次數(shù):
真彩色:沒有過度繪制
藍色:過度繪制 1 次
綠色:過度繪制 2 次
粉色:過度繪制 3 次
紅色:過度繪制 4 次或更多次
總之,盡量避免過度繪制,常見的就是設置了多個背景顏色造成
內存優(yōu)化
在開發(fā)的過程获印,如果方法不當?shù)脑挘苋菀自斐蓛却嫘孤┙种荩酉聛砑娣幔瑏碚f一下哪些情景容易出現(xiàn)內存泄漏。
內存泄漏出現(xiàn)的情景
單例中引用的上下文Context唆缴,引用了Activity中的Context, 這樣會造成內存泄漏鳍征,要引用Application中的Context;()參考文章
盡量不要在Activity中使用非靜態(tài)內部類,因為非靜態(tài)內部類會隱式持有外部類實例的引用面徽,如果使用靜態(tài)內部類艳丛,將外部實例引用作為弱引用持有。
資源性對象未關閉趟紊。比如Cursor氮双、File文件等,往往都用了一些緩沖霎匈,在不使用時戴差,應該及時關閉它們。參考文章
注冊對象未注銷铛嘱。比如事件注冊后未注銷暖释,會導致觀察者列表中維持著對象的引用。類的靜態(tài)變量持有大數(shù)據(jù)對象墨吓。例如EventBus或者RxJava
使用MMKV替換SharePreference(就是以鍵值對形式存在xml文件中)
速度優(yōu)勢:寫入速度是SharedPreferences的100倍左右球匕。在主線程做IO存儲 用mmkv一點問題都沒有,不會出現(xiàn)卡頓情況,特別是在數(shù)據(jù)量比較大的時候帖烘,速度會一直保持在10ms以內
寫入安全:通過 mmap 內存映射文件亮曹,提供一段可供隨時寫入的內存塊,App 只管往里面寫數(shù)據(jù),由操作系統(tǒng)負責將內存回寫到文件乾忱,不必擔心 crash 導致數(shù)據(jù)丟失讥珍。
寫入優(yōu)化:SharedPreferences在本身數(shù)據(jù)量比較多的情況下,更新一個key-value時窄瘟,會發(fā)生全量寫入衷佃,意味著時間更長。mmkv避免了這種情況的出現(xiàn)蹄葱。mmkv以增量方式進行寫入
功能更全:支持多進程訪問氏义,支持數(shù)據(jù)加密。多線程安全寫入
參考文件非靜態(tài)內部類的靜態(tài)實例图云。參考文章
public class LayoutPerActivity extends Activity {
private static TestModule mTestModule = null;
@override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getWindow().setBackgroundDrawable(null);
setContentView(R.layout.activity_layout_per);
if(null == mTestModule) {
mTestModule = new TestModule(this);
}
}
class TestModule{
private Context mContext = null;
public TestModule(Context ctx) {
mContext = ctx;
}
}
}
Handler臨時性內存泄漏惯悠。如果Handler是非靜態(tài)的,容易導致 Activity 或 Service 不會被回收,或者可以使用弱引用持有對Activity的引用竣况。
容器中的對象沒清理造成的內存泄漏克婶。
WebView。WebView 存在著內存泄漏的問題丹泉,在應用中只要使用一次 WebView情萤,內存就不會被釋放掉。參考資料
內存優(yōu)化的方案
- 對象引用摹恨。強引用筋岛、軟引用、弱引用晒哄、虛引用四種引用類型睁宰,根據(jù)業(yè)務需求合理使用不同,選擇不同的引用類型寝凌。
- 減少不必要的內存開銷柒傻。注意自動裝箱,增加內存復用硫兰,比如有效利用系統(tǒng)自帶的資源诅愚、視圖復用、對象池劫映、Bitmap對象的復用违孝。
- 使用最優(yōu)的數(shù)據(jù)類型。比如針對數(shù)據(jù)類容器結構泳赋,可以使用ArrayMap數(shù)據(jù)結構雌桑,避免使用枚舉類型,使用緩存Lrucache等等祖今。
- 圖片內存優(yōu)化校坑〖鸺迹可以設置位圖規(guī)格,根據(jù)采樣因子做壓縮耍目,用一些圖片緩存方式對圖片進行管理等等膏斤。
除此之外,內存泄漏可監(jiān)控, 推薦square公司開源的Leakcanary可以在發(fā)生內存泄漏時告警邪驮,并且生成 leak tarce 分析泄漏位置莫辨,同時可以提供 Dump 文件進行分析。
內存分析工具
以下介紹幾種內存分析工具
-
Memory Monitor
Memory Monitor 是一款使用非常簡單的圖形化工具毅访,可以很好地監(jiān)控系統(tǒng)或應用的內存使用情況.
主要有以下功能:
(1).顯示可用和已用內存沮榜,并且以時間為維度實時反應內存分配和回收情況。
(2).快速判斷應用程序的運行緩慢是否由于過度的內存回收導致喻粹。
(3).快速判斷應用是否由于內存不足導致程序崩潰蟆融。
- Allocation Tracker
Memory Monitor 和 Heap Viewer 都可以很直觀且實時地監(jiān)控內存使用情況,還能發(fā)現(xiàn)內存問題守呜,但發(fā)現(xiàn)內存問題后不能再進一步找到原因型酥,或者發(fā)現(xiàn)一塊異常內存,但不能區(qū)別是否正常查乒,同時在發(fā)現(xiàn)問題后冕末,也不能定位到具體的類和方法。這時就需要使用另一個內存分析工具 Allocation Tracker侣颂,進行更詳細的分析, Allocation Tracker 可以分配跟蹤記錄應用程序的內存分配枪孩,并列出了它們的調用堆棧憔晒,可以查看所有對象內存分配的周期。
- Memory Analyzer Tool(MAT)
MAT 是一個快速蔑舞,功能豐富的 Java Heap 分析工具拒担,通過分析 Java 進程的內存快照 HPROF 分析,從眾多的對象中分析攻询,快速計算出在內存中對象占用的大小从撼,查看哪些對象不能被垃圾收集器回收,并可以通過視圖直觀地查看可能造成這種結果的對象钧栖。
-
AndroidPerformanceMonitor
非侵入式的性能監(jiān)控組件低零,通知形式彈出卡頓信息
implementation 'com.github.markzhai:blockcanary-android:1.5.0'
當我們把程序運行之后,會發(fā)現(xiàn)手機桌面上出現(xiàn)了一個Blocks的圖標拯杠,這個玩意和之前我們使用LeakCanary的時候有點像哈掏婶,然后點進去果然發(fā)現(xiàn)了剛剛的Block信息
代碼優(yōu)化
關于代碼優(yōu)化,有這么一個很好用的工具Android lint
在頂部菜單欄找到Analyze選項,在彈框中選中Inspect Code,或者對項目根雙擊彈出菜單彈框(windows下右鍵項目根目錄)潭陪,找到Analyze選項再選中Inspect Code選項
Correctness:不夠完美的編碼雄妥,比如硬編碼最蕾、使用過時 API 等
Performance:對性能有影響的編碼,比如:靜態(tài)引用老厌,循環(huán)引用等
Internationalization:國際化瘟则,直接使用漢字,沒有使用資源引用等
Security:不安全的編碼枝秤,比如在 WebView 中允許使用 JavaScriptInterface
Remove All Unused Resources的選項,先全部清理,考慮反射機制,不能刪除資源
Handler Reference leaks,當使用內部類(包括匿名類)來創(chuàng)建Handler的時候醋拧,Handler對象會隱式地持有一個外部類對象(通常是一個Activity)的引用(不然你怎么可能通過Handler來操作Activity中的View?)宿百。而Handler通常會伴隨著一個耗時的后臺線程(例如從網絡拉取圖片)一起出現(xiàn)趁仙,這個后臺線程在任務執(zhí)行完畢(例如圖片下載完畢)之后,通過消息機制通知Handler垦页,然后Handler把圖片更新到界面雀费。然而,如果用戶在網絡請求過程中關閉了Activity痊焊,正常情況下盏袄,Activity不再被使用,它就有可能在GC檢查時被回收掉薄啥,但由于這時線程尚未執(zhí)行完辕羽,而該線程持有Handler的引用(不然它怎么發(fā)消息給Handler?)垄惧,這個Handler又持有Activity的引用刁愿,就導致該Activity無法被回收(即內存泄露),直到網絡請求結束(例如圖片下載完畢)到逊。另外铣口,如果你執(zhí)行了Handler的postDelayed()方法,該方法會將你的Handler裝入一個Message觉壶,并把這條Message推到MessageQueue中脑题,那么在你設定的delay到達之前,會有一條MessageQueue -> Message -> Handler -> Activity的鏈铜靶,導致你的Activity被持有引用而無法被回收叔遂。這個問題也是較常見的可能導致內存泄漏的問題,解決方法一般是通過弱引用持有對Activity的引用
Android代碼優(yōu)化——Layout Inspector
當您的布局在運行時構建而不是完全在XML布局中定義時争剿,這尤其有用
Layout Inspector主要用分析布局的層級結構已艰,減少不必要的層級,避免overdraw, 達到渲染優(yōu)化的效果蚕苇。Layout Inspector雖然界面不如HierarchyView直觀旗芬,但是提供的信息也足夠詳細,分析布局層級絕對夠用了捆蜀。
Android代碼優(yōu)化---traceview使用
Debug.startMethodTracing(“hello”); Debug.stopMethodTracing();
TraceView 是 Android SDK 中內置的一個工具疮丛,它可以加載 trace 文件幔嫂,用圖形的形式展示代碼的執(zhí)行時間、次數(shù)及調用棧誊薄,便于我們分析履恩。
trace 文件是 log 信息文件的一種,可以通過代碼呢蔫,Android Studio切心,或者 DDMS 生成。
使用luban壓縮 是通過原生的bitmap.compress() 是1000倍,參考微信,手機拍照幾M上傳上去就幾十KB
耗電優(yōu)化
在移動設備中片吊,電池的重要性不言而喻绽昏,沒有電什么都干不成。對于操作系統(tǒng)和設備開發(fā)商來說俏脊,耗電優(yōu)化一致沒有停止全谤,去追求更長的待機時間,而對于一款應用來說爷贫,并不是可以忽略電量使用問題认然,特別是那些被歸為“電池殺手”的應用,最終的結果是被卸載漫萄。因此卷员,應用開發(fā)者在實現(xiàn)需求的同時,需要盡量減少電量的消耗腾务。 耗電的原因其實很多毕骡,這里我就講一下幾種優(yōu)化方案,優(yōu)化方案的反面就是他的原因了岩瘦,幾種優(yōu)化方案如下:
合理的使用wack_lock鎖挺峡,wake_lock鎖主要是相對系統(tǒng)的休眠(這里就是為了省電,才做休)而言的担钮,意思就是我的程序給CPU加了這個鎖那系統(tǒng)就不會休眠了,這樣做的目的是為了全力配合我們程序的運行尤仍。有的情況如果不這么做就會出現(xiàn)一些問題箫津,比如微信等及時通訊的心跳包會在熄屏不久后停止網絡訪問等問題。所以微信里面是有大量使用到了wake_lock鎖宰啦。這里有一篇關于wake_lock的使用苏遥,請查閱;
使用jobScheduler2赡模,集中處理一些網絡請求田炭,有些不用很及時的處理可以放在充電的時候處理,比如漓柑,圖片的處理教硫,APP下載更新等等叨吮,這里有一篇關于jobScheduler的使用,請查閱瞬矩;
計算優(yōu)化茶鉴,避開浮點運算等。
數(shù)據(jù)在網絡上傳輸時景用,盡量壓縮數(shù)據(jù)后再傳輸涵叮,建議用FlatBuffer序列化技術,這個比json效率高很多倍伞插,不了解FlatBuffer割粮,建議找資料學習一下,后面有時間的話媚污,也會專門寫關于FlatBuffer的文章.
andriod耗電分析所用到的工具
在 Android5.0 以前舀瓢,在應用中測試電量消耗比較麻煩,也不準確杠步,5.0 之后專門引入了一個獲取設備上電量消耗信息的 API:Battery Historian氢伟。Battery Historian 是是一款圖形化數(shù)據(jù)分析工具,直觀地展示出手機的電量消耗過程幽歼,通過輸入電量分析文件朵锣,顯示消耗情況;
安裝包大小優(yōu)化
隨著功能不斷增加甸私,APP的包肯定不會斷的變大诚些,但應用的安裝包越大,用戶下載的門檻越高皇型,特別是在移動網絡情況下诬烹,用戶在下載應用時,對安裝包大小的要求更高弃鸦,因此绞吁,減小安裝包大小可以讓更多用戶愿意下載和體驗產品。所以唬格,我們還是要想辦法去如何去優(yōu)化家破,盡量減小app的安排包.
APP包優(yōu)化方案
-
res資源優(yōu)化
(1)只盡量使用一套圖片,使用高分辨率的圖片购岗。
(2)UI設計在ps安裝TinyPNG插件汰聋,對圖片進行無損壓縮。
(3)svg圖片:一些圖片的描述喊积,犧牲CPU的計算能力的烹困,節(jié)省空間。使用的原則:簡單的圖標乾吻。
(4)圖片使用WebP(developers.google.com/speed/webp/)的格式(Facebook髓梅、騰訊拟蜻、淘寶在用。)缺點:加載相比于PNG要慢很多女淑。 但是配置比較高瞭郑。工具: isparta.github.io/
(5)使用tintcolor(android - Change drawable color programmatically)實現(xiàn)按鈕反選效果。 -
代碼優(yōu)化
(1)實現(xiàn)功能模塊的邏輯簡化
(2)Lint工具檢查無用文件將無用的資源列在“UnusedResources: Unused resources”鸭你,刪除屈张。
(3)移除無用的依賴庫。 -
lib資源優(yōu)化
(1)動態(tài)下載的資源袱巨。
(2)一些模塊的插件化動態(tài)添加阁谆。
(3)so文件的剪裁和壓縮。 -
assets資源優(yōu)化
(1)音頻文件最好使用有損壓縮的格式愉老,比如采用opus场绿、mp3等格式,但是最好不要使用無損壓縮的音樂格式
(2)對ttf字體文件壓縮嫉入,可以采用FontCreator工具只提取出你需要的文字焰盗。比如在做日期顯示時,其實只需要數(shù)字字體咒林,但是使用原有的字體庫可能需要10MB大小熬拒,如果只是把你需要的字體提取出來生成的字體文件只有10KB -
代碼混淆。
使用proGuard 代碼混淆器工具垫竞,它包括壓縮澎粟、優(yōu)化、混淆等功能欢瞪。 -
7z極限壓縮
具體請參考微信的安接包壓縮,實現(xiàn)實現(xiàn)原理活烙,有時間再分析;
穩(wěn)定性優(yōu)化
Android 應用的穩(wěn)定性定義很寬泛遣鼓,影響穩(wěn)定性的原因很多啸盏,比如內存使用不合理、代碼異常場景考慮不周全骑祟、代碼邏輯不合理等回懦,都會對應用的穩(wěn)定性造成影響。其中最常見的兩個場景是:Crash 和 ANR曾我,這兩個錯誤將會使得程序無法使用,比較常用的解決方式如下:
提高代碼質量健民。比如開發(fā)期間的代碼審核抒巢,看些代碼設計邏輯,業(yè)務合理性等秉犹。
代碼靜態(tài)掃描工具蛉谜。常見工具有Android Lint稚晚、Findbugs、Checkstyle啡彬、PMD等等把跨。
Crash監(jiān)控混槐。把一些崩潰的信息,異常信息及時地記錄下來也搓,以便后續(xù)分析解決。
Crash上傳機制涵紊。在Crash后傍妒,盡量先保存日志到本地,然后等下一次網絡正常時再上傳日志信息摸柄。
適當緩存颤练,可讓App看起來更快。
使用DiskLruCache驱负。
總結
其實app性能優(yōu)化嗦玖,不是一二天可以完成的,不斷的提高開發(fā)的質量跃脊,發(fā)現(xiàn)了問題宇挫,就要及時的解決,不能推三拉四,這次就總結到這里,本人也是小白,希望能能夠和大家一起學習.