性能的優化是一個老生常談的點,也是一個比較重要的點。作過一點性能優化的工做,如今對工做中的優化點作一個總結。若有錯誤,還請指正。html
有哪些方面須要優化
在平時的優化過程當中咱們須要從哪幾個點來優化呢?其實咱們平時本身必定也用過軟件,在使用軟件的過程當中有沒有什麼想吐槽的呢?java
「這個 app 怎麼還沒下載完!」、「太卡了吧!」、"圖片怎麼還沒加載出來!"、"怎麼剛進去就卡了!"、「這麼點了一下就退出了!」等等,是否是有這樣的想法?這些想法其實包含了咱們今天要說的內容,就是從哪些方面來優化咱們的 APP ,我總結了如下幾點。python
- APK 瘦身優化
- 啓動速度優化
- 穩定性優化
- 內存的優化
- 操做流暢度優化
固然,須要優化的不只僅是這幾個方面,我作的比較多的優化是這幾個方面,暫時就這幾個方面來談談優化吧。linux
APK 瘦身
如何查看 APK 的組成
若是要優化 APK 的大小,咱們首先須要知道咱們編譯出來的 APK 都包含哪些東西,而後針對佔用大的作裁剪,或者刪除不須要的東西,從而達到瘦身的目的。android
查看 APK 的內容佔用狀況很簡單,打開 AS ,把 APK 拖到 AS 裏面就能夠查看 APK 包含的內容了。git
能夠看到佔大頭的是 res 代碼等,因此瘦身能夠從這幾個方面來考慮。github
如何減小 res 資源大小
- 刪除冗餘的資源
通常隨着項目的迭代,部分圖片等資源再也不使用了,可是可能仍然被編譯到了 apk 裏面,因此能夠刪除這部分再也不使用的資源,可使用 lint 工具來搜索項目中再也不使用的圖片等資源。shell
- 重複資源的優化
除了有冗餘資源,還有些是文件名不同,可是內容同樣的圖片,能夠經過比較 md5 值來判斷是否是同樣的資源,而後編輯 resources.arsc 來重定向。瀏覽器
- 圖片壓縮
未壓縮的圖片文件佔用空間較大,能夠考慮壓縮未壓縮過的圖片來瘦身。經常使用的工具是 tinypng 網站。性能優化
同時也能夠藉助 TinyPngPlugin 等插件或者其餘開源工具來幫助壓縮圖片。
- 資源混淆
經過將資源路徑 res/drawable/wechat
變爲 r/d/a
的方式來減小 apk 的大小,當 apk 有較多資源項的時候,效果比較明顯,這是一款微信開源的工具,詳細地址是:AndResGuard
- 指定語言
若是沒有特殊的需求的話,能夠只編譯中文,由於其餘的語言用不上,若是用不上的語言編譯了,會在 resource 的表裏面佔用大量的空間,故
android { defaultConfig { ... // 僅支持 中文 resConfigs "zh" } }
如何減小 so 庫資源大小
- 本身編譯的 so
release 包的 so 中移除調試符號。可使用 Android NDK 中提供的 arm-eabi-strip
工具從原生庫中移除沒必要要的調試符號。
若是是 cmake 來編譯的話,能夠再編輯腳本添加以下代碼
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -s") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -s")
- 別人編譯的 so
聯繫做者修改,通常很難聯繫到。
- 動態下發 so
能夠經過服務器下發 so , 下載完後再進入應用,可是體驗很差,可是是一個思路。
- 只編譯指定平臺的 so
通常咱們都是給 arm 平臺的機器開發,若是沒有特殊狀況,咱們通常只須要考慮 arm 平臺的。具體的方法是 app 下的 build.gradle 添加以下代碼
android { defaultConfig { ndk { abiFilter "armeabi" } } }
各個平臺的差異以下:
平臺 | 說明 |
---|---|
armeabi-v7a | arm 第 7 代及以上的處理器,2011 年後的設備基本都是 |
arm64-v8a | arm 第 8 代 64 位處理器設備 |
armeabi | arm 第 五、6 代處理器,早期的機器都是這個平臺 |
x86 | x86 32 位平臺,平板和模擬器用的多 |
x86_64 | x86 64 位平臺 |
如何減小代碼資源大小
- 一個功能儘可能用一個庫
好比加載圖片庫,不要 glide 和 fresco 混用,由於功能是相似的,只是使用的方法不同,用了多個庫來作相似的事情,代碼確定就變多了。
- 混淆
混淆的話,減小了生成的 class 大小,這樣聚沙成塔,也能夠從必定層度減小 apk 的大小。
- R 文件內聯
經過把 R 文件裏面的資源內聯到代碼中,從而減小 R 文件的大小。
可使用 shrink-r-plugin 工具來作 R 文件的內聯
參考文檔
啓動速度
啓動的類型
通常分爲,冷啓動和熱啓動
> 冷啓動:啓動時,後臺沒有任何該應用的進程,系統須要從新建立一個進程,並結合啓動參數啓動該應用。
> 熱啓動:啓動時,系統已經有該應用的進程(好比按 home 鍵臨時退出該應用)下啓動該應用。
如何獲取啓動時間
- adb 命令
adb shell am start -S -W 包名/啓動類的全名
adb shell am start -S -W xxx/xxxActivity Stopping: xxx Starting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=xxx/xxxActivity } Status: ok Activity: xxx/xxxActivity ThisTime: 770 TotalTime: 770 WaitTime: 848 Complete
ThisTime: 表示最後一個 Activity 啓動時間
TotalTime: 表示啓動過程當中,全部的 Activity 的啓動時間
WaitTime: 表示應用進程的建立時間 + TotalTime
通常咱們關注 TotalTime
就行了。
另外,谷歌在 Android4.4(API 19)上也提供了測量方法,在 logcat 中過濾 Displayed 字段也能夠看到啓動時間
> 2021-04-06 19:25:52.803 2210-2245 I/ActivityManager: Displayed xxx/xxxActivity: +623ms
+623ms
就是Activity 的啓動時間。
- 時間戳
時間戳的方法基於如下的 2 個知識點。
- 應用進程剛建立,會調用 Application 的 onCreate 方法。
- 首次進入一個 Activity 後會在 onResume() 方法後面調用 onWindowsFocusChange 方法。
結合這 2 個特性,咱們能夠在 A Application 的 onCreate() 方法和 Activity 的 onWindowsFocusChange 方法裏面,經過時間戳來獲取應用的冷啓動時間。
如何監控啓動過程
- systrace
systrace 是一個功能很強大的工具,除了能夠查看卡頓問題,也能夠用來查看應用的啓動問題。使用示例以下:
> python $ANDROID_HOME/platform-tools/systrace/systrace.py gfx view wm am pm ss dalvik app sched -b 90960 -a 你的包名 -o test.log.html
用 Google 瀏覽器打開 test.log.html
就能夠看到詳細的啓動信息。
- Debug 接口
package android.os; ... class Debug { ... public static void startMethodTracingSampling(String tracePath, int bufferSize, int intervalUs) { } public static void startMethodTracing(String tracePath, int bufferSize) { } }
利用 Debug 類的這兩個方法,能夠生成一個 trace
文件,這個 trace
文件,能夠直接在 AS
裏面打開,能夠看到從 startMethodTracingSampling
到 startMethodTracing
過程當中的方法調用等信息,也能夠較好的分析啓動問題。
通常有那些優化方法
- 耗時操做放到異步進程
好比文件解壓、讀寫等耗時 IO 操做能夠新開一個線程來執行。
- 延時初始化
即暫時不適用的工具類等延後到使用的時候再去初始化。好比從 xml 裏面讀取顏色,能夠考慮在使用的時候再去讀取和解析。
- 線程優化
線程的建立須要消耗較多的系統系統資源,減小線程的建立。能夠考慮共用一個線程池。
如何檢測線程的建立,能夠參考我個開源庫 performance
穩定性優化
APP 穩定性的維度
app 穩定通常指的是 app 能正常運行, app 不能正常運行的狀況分爲兩大類,分別是 Crash
和 ANR
> Crash:運行過程當中發生的錯誤,是沒法避免的。
> ANR:應用再運行時,因爲沒法再規定的時間段內響應完,系統作出的一個操做。
如何治理 Crash
應用發生 Crash 是因爲應用在運行時,應用產生了一個未處理的異常(就是沒有被 try catch 捕獲的異常)。這會致使 app 沒法正常運行。
若是須要解決的話,就須要知道這個未處理的異常是在哪裏產生的,通常是經過分析未處理的異常的方法調用堆棧來解決問題。
Android APP 能夠分爲 2 層,Java 層和 Native 層。因此如何捕獲須要分開說。
Java 層獲取未處理的異常的調用堆棧
這個須要瞭解 Java
虛擬機是如何把一個未捕獲的異常報上來的。
未捕獲的異常,會沿着方法的調用鏈依次上拋,直到 ThreadGroup
的 uncaughtException
方法
public void uncaughtException(Thread t, Throwable e) { if (parent != null) { // 遞歸調用,能夠忽略 parent.uncaughtException(t, e); } else { // 交給了 Thread.getDefaultUncaughtExceptionHandler() 來處理未捕獲的異常 Thread.UncaughtExceptionHandler ueh = Thread.getDefaultUncaughtExceptionHandler(); if (ueh != null) { ueh.uncaughtException(t, e); } else if (!(e instanceof ThreadDeath)) { System.err.print("Exception in thread \"" + t.getName() + "\" "); e.printStackTrace(System.err); } } }
查閱代碼發現,發現 ThreadGroup
最終會給 Thread
的 defaultUncaughtExceptionHandler
處理。
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
上面的代碼顯示:Thread
的 defaultUncaughtExceptionHandler
是 Thread
類的一個靜態變量。
看到這裏,如何捕獲 Java
層未處理的異常就很清晰了,給 Thread
設置一個新的 defaultUncaughtExceptionHandler
,在這個新的 defaultUncaughtExceptionHandler
裏面收集須要的信息就能夠了。
須要注意的一點是 舊的 defaultUncaughtExceptionHandler
須要保存下來,而後新的 defaultUncaughtExceptionHandler
收集信息後,須要再轉給舊的 defaultUncaughtExceptionHandler
繼續處理。
Native 層獲取未處理的異常的相關信息
Java 層如何收集未處理的異常的信息說過了,咱們來看看 Native 層發生未處理的異常的話,是如何處理的。 Native 層的處理,須要掌握 linux 的一些知識,因爲本人不是特別瞭解 linux ,這裏就直接參考別人的文章了。若是有錯誤,還請指正。
本人經過查閱資料發現,Native 層若是發生未處理的異常(注:若是 Native 層捕獲了異常,是能夠經過 JNI 拋到 Java 層去處理的) ,系統會發出信號給 Native 層,在 Native 層若是要收集未處理的異常信息,就須要註冊對應信號的處理函數。當發生異常的時候,Native 層會收到信息,而後經過處理器來收集信息。
註冊信號處理函數以下:
#include <signal.h> int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));
- signum:表明信號編碼,能夠是除SIGKILL及SIGSTOP外的任何一個特定有效的信號,若是爲這兩個信號定義本身的處理函數,將致使信號安裝錯誤。
- act:指向結構體sigaction的一個實例的指針,該實例指定了對特定信號的處理,若是設置爲空,進程會執行默認處理。
- oldact:和參數act相似,只不過保存的是原來對相應信號的處理,也可設置爲NULL。
有了信號處理函數,後面還要作的事情就是收集信息了,因爲本人不是很熟悉 Native 的開發,這裏就不展開說了了,你們能夠參考 Android 平臺 Native 代碼的崩潰捕獲機制及實現。
如何治理 ANR
ANR
是 Applicatipon No Response
的簡稱。若是應用卡死或者響應過慢,系統就會殺死應用。爲何要殺死應用?其實也很好理解,若是不殺死應用,你們會覺得系統壞了。
那咱們如何監控 ANR
呢?以及咱們如何分析 ANR 的問題呢?常見的致使 ANR 的緣由有哪些呢?
首先,ANR
的原理是 AMS
在 UI 操做
開始的時候,會根據 UI 操做
的類型開啓一個延時任務,若是這個任務被觸發了,就表示應用卡死或者響應過慢。這個任務會在 UI 操做
結束的時候被移除。
而後,如何分析 ANR
問題呢?
通常 ANR
發生的時候, logcat
裏面會打印 ANR
相關的信息,過濾關鍵字 ANR
就能夠看到,這裏不作詳細分析,能夠參考後面的文章。
而後通常會在 /data/anr
目錄下面生成 traces.txt
文件,裏面通常包含了 ANR
發生的時候,系統和全部應用的線程等信息(須要注意的是,不一樣的 rom 可能都不同),經過 logcat
打印的信息和 traces.txt
裏面的信息,大部分的 ANR
能夠分析出緣由,可是呢,也有至關一部分的 ANR 問題沒法分析,由於 logcat
和 traces.txt
提供的信息有限,有時候甚至沒有特別有用的信息,特別是 Android
的權限收緊, traces.txt
文件在高 Android 版本
沒法讀取,給 ANR
問題的分析增長了很多的困難。不過好在最近發現頭條給 ANR
寫了一個系列的文章,裏面對 ANR 問題的治理方法,我的以爲很好,這裏引用一下。
- 今日頭條 ANR 優化實踐系列 - 設計原理及影響因素
- 今日頭條 ANR 優化實踐系列 - 監控工具與分析思路
- 今日頭條 ANR 優化實踐系列分享 - 實例剖析集錦
- 今日頭條 ANR 優化實踐系列 - Barrier 致使主線程假死
本人以前寫過一個小的性能監測的工具,其中有監控 UI
線程 Block
的功能,考慮後續加入頭條的 ANR
監測機制,等後續完成了,在作一個詳細的總結吧。此次的總結就寫到這裏。
內存的優化
硬件的內存老是有限的,全部每一個應用分到的內存也是有限的,全部內存的優化頗有必要,不然應用就沒有足夠的內存使用了,這個時候就會 Crash 。
內存都消耗在哪裏了
優化內存的話,須要瞭解內存在哪裏消耗了了,針對內存消耗大的場景作優化,對症下藥,才能夠有一個好的優化效果。
Android Studio
裏面的 Profiler
工具是一個很好用的工具,經過裏面的 memory
工具能夠實時監控
APP 運行過程當中的內存分配。
dump APP 內存堆棧後,還能夠看到各個類佔用的內存狀況。
能夠查看每一個對象的詳細信息。
Android Studio
裏面的 Profiler
工具的具體使用教程請參考官方教程,這裏就不作詳細介紹了。
如何合理使用內存
利用上面的方法,找到內存消耗大的場景,就須要作優化了,主要作法就是想辦法減小特定場景下的內存的使用。我的總結了一下平時可能會作的優化。
- 圖片相關的優化
圖片是我目前作的應用裏面佔用內存比較大的一塊了,也碰到了一些問題,我主要是經過如下的方法來作優化。
- 暫時用不上的圖片不加載,好比說,有個網絡加載異常的圖,不要一開始就初始化,等到真的有異常了須要展現的時候再初始化
- 加載圖片的時候,儘可能加載指定大小的圖片,由於有時候會碰到控件的大小小於實際圖片尺寸的狀況,這個時候,會浪費一些內存。有須要的話,可讓後臺返回不一樣尺寸的圖片。
- 根據不一樣的圖片格式
- 不顯示的圖片,能夠考慮先釋放。
- 儘量少地建立對象
毫無疑問,若是對象少,內存確定也消耗的少,那平時須要注意哪些呢?
- 自定義 view 的時候,不要在 onDraw 方法裏面頻繁建立對象。由於 onDraw 方法可能會頻繁調用,這個時候就會建立大量的對象。從而形成浪費,同時也會致使 gc 觸發的頻率升高,形成卡頓。
- 儘可能少建立線程,建立線程實際上是比較消耗資源的,建立一個空的線程,大概會佔用 1-2 M 內存。同時通常異步任務很快就會執行完,若是頻繁建立線程來作異步任務,除了內存使用的多,還可能 GC 形成卡頓。執行異步任務的話,通常建議用線程池來執行,可是須要注意線程池的使用。
- 儘可能用 StringBuilder 或者 StringBuffer 來拼接字符串。平時發現的問題主要是在打印 logcat 的時候和拼接後臺返回的數據的時候會建立大量的 String,因此若是有相似的狀況也能夠考慮作一些優化。
內存泄漏是什麼
內存泄漏指的是本應該釋放的內存,因爲一些緣由,被 GC ROOT 對象持有,從而而沒法在 GC 的時候釋放,這樣可能會致使的一個問題就是,重複操做之後,APP 沒有足有的內存使用了,這個時候系統會殺死 APP 。因此內存泄漏是須要排查的。
如何監控和分析內存泄漏問題
上一個小結總結了上面是內存泄漏,是由於某些 GC ROOT 對象持有了指望釋放的對象,致使指望釋放的內存沒法及時釋放。因此如何監控和分析內存泄漏問題就成了如何找到 GC ROOT 的問題。
通常手動分析的步驟是:重複操做懷疑有內存泄漏的場景,而後觸發幾回 GC 。等幾秒鐘後,把 APP 的內存堆棧 dump 下來(可使用 as 的工具 dump),而後用 sdk 裏面的 cover 工具轉換一下,而後用 MAT 工具來分析內存泄漏的對象到 GC ROOT 的引用鏈。
手動分析老是很麻煩的,一個好消息是,有一個特別好用的自動監控和分析內存泄漏的工具,這個工具就是 leakcanary ,它能夠自動監控並給出內存泄漏的對象到 GC ROOT 的引用鏈。
使用很簡單,只須要在 APP 的 build.gradle 下面新增
dependencies { // debugImplementation because LeakCanary should only run in debug builds. debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7' }
leakcanary 比較核心的一個原理就是利用了弱引用的一個特性,這個特性就是:
> 在建立弱引用的時候,能夠指定一個 RefrenceQueue ,當弱引用引用的對象的可達性發生變化的時候,系統會把這個弱引用引用的對象放到以前指定的 RefrenceQueue 中等待處理。
因此 GC 後,引用對象仍然沒有出如今 RefrenceQueue 的時候,說明可能發生了內存泄漏,這個時候 leakcanary 就會 dump 應用的 heap ,而後用 shark 庫分析 heap ,找出一個到 GC ROOT 的最短引用鏈並提示。
常見的內存泄漏的場景
我的總結了下工做中碰到內存泄漏的一些場景,現記錄下來,你們能夠參考下。
- 靜態變量持有 Context 等。
- 單例實例持有 Context 等。
- 一些回調沒有反註冊,好比廣播的註冊和反註冊等,有時候一些第三方庫也須要注意。
- 一些 Listener 沒有手動斷開鏈接。
- 匿名內部類持有外部類的實例。好比 Handler , Runnable 等常見的用匿名內部類的實現,經常會不當心持有 Context 等外部類實例。
操做流暢度優化
爲何會卡頓
爲何卡頓以前,咱們先須要簡單瞭解一點硬件相關的知識。就是在界面繪製的過程當中, CPU 主要的任務是計算出屏幕上全部 View 對應的圖形和向量等信息。 GPU 的主要任務就是把 CPU 計算出的圖形柵格化並轉化爲位圖,能夠簡單理解爲屏幕像素點對應的值。
若是操做過程當中卡頓了,通常就是 CPU 和 GPU 其中的一個或者多個沒法短期完成對應的任務。
通常而言,CPU 除了須要計算 View 對應的圖形和向量等信息,還要作邏輯運算和文件讀寫等任務,因此 CPU 形成卡頓更常見。通常也是經過減小 CPU 的計算任務來優化卡頓。
影響 CPU 的使用率通常有如下幾個方面:
- 讀寫文件
- 解析大量圖片
- 頻繁請求網絡
- 複雜的佈局
- 頻繁建立對象
如何檢測卡頓
雖然咱們知道了大概哪些緣由會致使卡頓,可是咱們沒法準肯定位出問題的代碼點在哪裏,針對上面的部分問題,本人寫了一個開源庫來自動檢測,這個開源庫的地址是
> https://github.com/XanderWang/performance
詳細的原理,能夠參考上面的鏈接,這裏簡單總結下監控 UI 卡段的原理。
咱們知道,Android
裏面,界面的刷新須要再主線程或者說 UI 線程執行。而界面的繪製起始點又利用了 Looper 消息循環
機制。Looper 消息循環
機制有一個有意思的特色,就是 Looper 在 dispatch
Message 的時候,會在 dispatch 前
和 dispatch 後
利用 Printer
打印特定 tag
的字符串,經過接管 Printer
,咱們就能夠獲取 dispatch message
先後的時機。
而後咱們能夠在 dispatch message 以前
,在異步線程
啓動一個抓取系統信息的延時任務。在 dispatch message 以後
,咱們能夠移除
異步線程的這個延時任務。若是某個消息的執行沒有超過閾值,那就表示在異步線程的延時任務被取消,代表沒有卡頓。若是某個消息的執行時間超過了閾值,那異步線程裏的延時任務就會執行,代表有卡頓,異步線程的延時任務會獲取此時的系統狀態,從而輔助咱們分析卡頓問題。
如何優化卡頓
如何檢測說完了,咱們來講說如何優化。在 爲何會卡頓 小結我總結了幾種常見,如今對幾種場景的優化總結下。
讀寫文件
最多見的一個讀寫文件而不自知的就是 SharePerfrences
的使用,使用 sp
的時候須要注意不要頻繁調用 apply
或者 commit
方法,由於每調用一次就有可能會有一次寫文件操做(高版本系統作了優化 apply 作了優化,不必定會寫文件)。因此,若是調用次數多的話,就會屢次寫文件,寫文件又是一個耗時且耗資源的操做,因此要少作。
通常優化方法是合理拆分
sp 文件,一個 sp 文件不要包含太多的項,同時每一項的內容儘可能短。儘可能批量提交數據後再 commit 或者 apply 。同時須要注意的是 commit 會直接觸發寫文件(內容有變化的時候),因此若是在 UI 線程調用 commit 方法須要注意可能會阻塞 UI 線程。
若是有更高的性能需求,能夠考慮用 mmkv 來替換或者 DataStore 來替換 sp 。具體的替換方法就不細說了。網上有不少資料參考。
另一個常見的讀寫文件的場景是從 xml 文件裏面讀取佈局、色值等操做,這些都是一些 io 操做。從 xml 讀取佈局的話,能夠考慮用代碼直接建立 view 來優化,從 xml 裏面讀取顏色能夠考慮加個 HashMap 來優化。
解析大量圖片
解碼圖片毫無疑問是一個計算量大的操做,因此通常加載圖片的時候最好根據實際顯示的尺寸作壓縮,而且保存壓縮後的縮略圖,方便下次直接加載。
另外還須要注意列表滾動過程當中,控制對圖片的加載,通常列表在滑動過程當中,不加載圖片,等列表滾動中止後,纔開始加載圖片。
另外的一個優化的方法就是減小圖片的使用,不過這個難度有點大。
另外還能夠考慮針對不一樣的圖片格式,用不一樣的解碼格式。好比 png
格式的圖片根據機器實際狀況選擇 8888
或者 4444
解碼方式解碼圖片。若是是 jpg/jpeg
格式的圖片,就用 565
的解碼方式解碼圖片。對於用不一樣的解碼方式解碼圖片,效率是否會高,本人沒作過測試,可是毫無疑問,內存的使用是不一樣的。
頻繁請求網絡
網絡請求的話,能夠參考下面的優化方法。
-
若是使用
okhttp
請求網絡的話,儘可能全局使用一個httpclient
,這樣作的好處是能夠複用,提升網絡請求效率。 -
後臺支持的話,開啓
gzip
壓縮,這樣網絡傳輸的數據量小些,傳輸效率會高些。 -
自定義
dns
,減小解析dns
的時間。 -
經過和後臺商量,部分數據後臺接口一步到位,儘可能避免屢次請求後纔拿到完整的目標數據。
複雜的佈局
若是佈局複雜的話, CPU 要進行大量的計算才能夠肯定最終的圖形。因此佈局複雜的話,CPU 須要大量的運算資源,因此優化複雜的佈局是頗有必要的。
-
減小布局層次,能夠利用 ViewStub 、merge 和 include 等標籤來嘗試減小布局層次。
-
使用高效的佈局容器,好比 ConstraintLayout,能夠不用嵌套佈局容器來實現複雜效果。
-
部分效果能夠考慮用自定義 View 實現。
這個優化感受不是特別好作,可能優化了,可是效果很差,可是又不能不作。
頻繁建立對象
爲何這個要列出來呢?由於頻繁建立對象,可能會短期內消耗大量內存,而後內存不足的時候系統就會嘗試 GC 來回收對象,而 GC 是很耗資源的操做,雖然如今 Android 系統對 GC 作了不少優化,可是儘可能減小 GC 的觸發老是好的。
通常頻繁建立對象的場景有:
- 自定義 View 的時候,在 onDraw 方法建立臨時對象
- 循環裏面使用 "+" 拼接字符串
- ArrayList 等有容積限制的容器類初始化的容量不合理,致使後續新增數據頻繁擴容。
可能還有一些場景沒有列出來,若是你們有好的建議,能夠提出來。
除了頻繁建立對象可能會觸發 GC ,若是某次使用過大的內存也可能會致使 GC ,好比展現一個超大的 Bitmap ,雖然能夠用縮略圖來展現,可是可能會碰到須要放大查看具體細節的場景,這個時候能夠考慮採用裁剪顯示區域(BitmapRegionDecoder)的方式來解析圖片。
小結
以上是我工做中涉及到的優化點,可能不是很全,也不免有遺漏。若是有錯誤和遺漏,還請你們指正。
聯繫我
-
Github: https://github.com/XanderWang
-
Mail: <420640763@qq.com>