歡迎來到 Android 開發老生常談的性能優化篇,本文將性能優化劃分為內存、網絡、布局、卡頓、安裝包、啟動速度七塊,從這七塊優化出發,闡述優化的 Application 的方式。
目錄
- 內存優化
- 避免內存泄漏
- 使用內存分析工具
- 優化數據結構和算法
- 數據緩存
- 避免頻繁的 GC
- 網絡優化
- 合并接口請求,減少請求次數
- 使用網絡緩存
- 使用合適的數據格式
- 使用合適的網絡庫
- 后臺同步
- 預加載
- 使用持久連接
- 優化圖片加載
- 使用前檢測網絡
- 布局優化
- 1、減少布局嵌套
- 2、減少 wrap-content 的使用
- 3、使用 include、merge、ViewStub,重復布局復用
- 卡頓優化
- 造成卡頓的原因
- 主線程阻塞
- 內存泄漏
- 布局過于復雜
- Bitmap對象過大
- 頻繁的GC
- 動畫效果處理不當
- 如何避免卡頓問題
- 避免在主線程中執行耗時操作
- 優化布局
- 處理內存泄漏
- 優化Bitmap的使用
- 減少GC的觸發
- 安裝包優化
- 資源優化
- 1、按需添加第三方庫,避免引入重復庫。
- 2、 png轉svg,再使用svg轉成vector格式。
- 3、 刪除多余的so庫。
- 4、 刪除多余的 `mipmap` 文件夾。
- 5、 刪除未使用到的資源文件。
- 6、動態加載.so文件。
- 7、使用插件化。
- 代碼混淆
- 啟動速度優化
- App Startup 優化初始化速度
- 懶加載
- ViewStup 按需加載布局
- Paging 分頁
- ViewPager 2 翻頁
- 預加載
- 偽加載
- 設置啟動頁
- 代碼優化
- 使用 adb 命令查看啟動 Activity 時間
- 使用 Profile 查看 Activity 方法耗時,對其進行優化
- WorkManager 后臺保活
- 課外小知識
- 應用啟動狀態
- 冷啟動
- 溫啟動
- 熱啟動
內存優化
在 Android 中,內存優化通常指的是 運行內存優化。運行內存優化 主要關注如何有效地使用和管理應用程序的 RAM (Random Access Memory) 使用,以提高性能,減少延遲,并防止應用程序因為消耗過多內存而被系統殺死。
避免內存泄漏
內存泄漏是指應用程序分配了內存,但未能釋放。這會導致應用程序消耗的內存隨著時間的推移而增加,可能導致應用程序崩潰或系統性能下降。
使用內存分析工具
Android Studio 提供了一些工具,如 Memory Profiler
,可以幫助開發者分析和理解應用程序的內存使用情況。
優化數據結構和算法
使用更有效的數據結構和算法可以減少內存使用。
數據緩存
合理使用 數據庫、網絡、圖片緩存數據,可以減少不必要的數據、重復數據的存儲,減少數據創建和銷毀的開銷,此外,還可以提高數據的訪問速度。
避免頻繁的 GC
垃圾回收 (Garbage Collection
簡稱 GC) ,頻繁的垃圾回收會影響應用程序的性能。可以通過減少對象的創建和銷毀,以及使用對象池等技術來減少垃圾回收的頻率。
網絡優化
合并接口請求,減少請求次數
盡可能地減少網絡請求次數,可以通過合并請求、使用批量接口等方式實現。
使用網絡緩存
對于一些不經常變動的數據,可以使用緩存來減少網絡請求。例如,可以使用 HTTP
緩存、數據庫緩存或者內存緩存。
使用合適的數據格式
例如,對于大量的數據,可以使用 Protobuf
而不是 JSON
,因為 Protobuf
更加緊湊,可以減少數據的大小,從而減少網絡傳輸的時間。
使用合適的網絡庫
使用 OkHttp
、Retrofit
等網絡庫,它們內部已經做了很多優化。
后臺同步
對于一些不需要立即返回結果的操作,可以使用后臺同步,例如使用 WorkManager
或者 JobScheduler
。
預加載
對于一些用戶可能需要的數據,可以提前進行加載。
使用持久連接
使用 HTTP2
,它們支持多路復用,可以減少連接的建立和關閉的開銷。
優化圖片加載
對于圖片,可以使用合適的格式和大小,還可以使用圖片加載庫,例如 Glide
或者 Picasso
,它們內部已經做了很多優化。
使用前檢測網絡
在進行網絡請求前,先檢測網絡狀態,如果網絡不可用,那么可以立即返回錯誤,而不是等待超時。
布局優化
1、減少布局嵌套
2、減少 wrap-content 的使用
3、使用 include、merge、ViewStub,重復布局復用
卡頓優化
在 Android 系統中,每一秒屏幕刷新速度為 60 幀(FPS),人類眼睛舒適放松時的可視幀率是 24 幀,當某個加載中的界面每秒刷新低于 24 幀時,就會感覺到卡頓。但當屏幕沒有繪制需求時,即屏幕的顯示的界面為靜止時,幀率為 0。
造成卡頓的原因
主線程阻塞
如果在主線程(UI線程)中執行了耗時的操作,如網絡請求、數據庫操作等,會導致UI更新延遲,從而引發卡頓。
內存泄漏
如果應用中存在內存泄漏,可能會導致內存占用過高,從而引發卡頓。
布局過于復雜
如果布局層級過深或者布局過于復雜,可能會導致布局渲染時間過長,從而引發卡頓。
Bitmap對象過大
如果Bitmap對象過大,可能會導致內存占用過高,從而引發卡頓。
頻繁的GC
垃圾回收 (Garbage Collection
簡稱 GC) 過程需要消耗系統資源,如果頻繁觸發,可能會導致應用性能下降,出現卡頓現象。
動畫效果處理不當
如何避免卡頓問題
避免在主線程中執行耗時操作
可以使用線程、協程、AsyncTask等技術將耗時操作移至后臺執行。
優化布局
盡量減少布局的層級,避免過度繪制,使用更高效的 View 或 ViewGroup。
處理內存泄漏
使用
LeakCanary
等工具幫助找到并處理內存泄漏。
優化Bitmap的使用
盡量不要使用過大的
Bitmap
,使用合適的壓縮格式和分辨率,及時回收不再使用的Bitmap
。
減少GC的觸發
盡量減少內存抖動,避免頻繁的對象創建和銷毀。 內存抖動 (
Memory Churn
) 是指應用程序在短時間內頻繁地創建和銷毀對象,這種行為會導致垃圾回收器 (Garbage Collector
) 頻繁地運行,從而消耗大量的CPU資源,可能導致應用程序的性能下降,出現卡頓現象。
以上只是一些可能的原因,具體的原因需要通過性能分析工具如 Android Profiler
、BlockCanary
、Systrace
等進行分析。
往期文章👉【Android】測試方法匯總,助力打造完美應用
安裝包優化
資源優化
1、按需添加第三方庫,避免引入重復庫。
2、 png轉svg,再使用svg轉成vector格式。
3、 刪除多余的so庫。
刪除多余的so庫,執行這一操作的前提是:程序所運行的系統 CPU 架構固定是 Android CPU 架構中的某一個。例如:部分第三方提供的 so 庫是包含了 armeabi
、armeabi-v71
、arm64-v8a
、x86
等庫文件,如果你的程序只運行在 armeabi
CPU 架構上,則可以把其它的 so 庫文件刪除。
4、 刪除多余的 mipmap
文件夾。
一般圖標資源使用 mipmap-xhdpi
足夠用了,更大的屏幕則使用 mipmap-xxhdpi
、mipmap-xxxhdpi
的分辨率,已經使用 mipmap-xhdpi
或其它更大分辨率的程序,應刪除比它小的分辨率文件。
5、 刪除未使用到的資源文件。
可通過 Android Studio 菜單欄的 Refactor
→ Remove Unused Resources
功能一鍵移除未被使用的 drawable
、mipmap
、layout
以及 colors.xml
、strings.xml
文件里面的 color
、string
。
6、動態加載.so文件。
.so
文件可以在用戶安裝應用到手機后再從服務器上下載到手機的 data
目錄下,加載的時候使用絕對路徑在 static
關鍵字里加載。
static {System.loadLibrary("so文件")
}
參考文章
1、Android 應用資源概述
7、使用插件化。
插件化技術支持動態加載代碼和動態加載資源,把 Application
的一部分分離出來,對于業務龐大的項目非常有用,極大的分解了 Application
的大小。但又因為插件化需要一定的技術保障和服務端的系統支持,有一定的風險,建議酌情選擇。
代碼混淆
代碼混淆(Obfuscation)是將計算機程序的源代碼或機器代碼,轉換成功能上等價,但是難于閱讀和理解的形式的行為。簡單來說,就是簡化函數名、變量、常量名稱,通過減少字符數以達到減小安裝包大小的方式。
啟用混淆只需要打開 Android 項目,在 Application Model 下中找到 build.gradle
,在該文件添加如下配置即可開啟混淆:
android {// 打包 release 包時執行release {// 啟用混淆,默認使用 R8 編譯器minifyEnabled true// 資源壓縮shrinkResources true// 定義 自定義混淆規則的文件proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}
}
上面混淆的方式僅適用于代碼簡單、封裝少的項目。項目復雜還請自定義混淆規則,詳情請查看往期文章👉【Android】App攻防之代碼混淆
啟動速度優化
App Startup 優化初始化速度
App Startup
是 Android 官方推出的一個應用程序啟動時初始化組件的庫。開發人員可以使用 App Startup
來簡化啟動序列并顯式設置初始化順序。
詳情請看👉 App Startup
懶加載
懶加載是一種延遲加載的策略,它指的是在需要時才進行加載和初始化,而不是在應用程序啟動或頁面加載時就提前加載。這種策略通常用于延遲加載大型資源或組件,以減少啟動時間和內存占用。
ViewStup 按需加載布局
詳情請看👉 ViewStup
Paging 分頁
詳情請看👉 Paging
ViewPager 2 翻頁
詳情請看👉 ViewPager 2
預加載
預加載是在應用程序啟動或特定頁面加載之前提前加載和準備數據、資源或組件。這有助于提高應用程序的性能和響應速度,因為一些必要的內容已經被提前加載到內存中,而不是等到用戶請求時再進行加載。
偽加載
偽加載是一種虛假的加載行為,通常用于模擬加載過程而不實際進行真正的加載。這種策略可以用于創建加載動畫或展示加載狀態,以提升用戶體驗,但實際上并沒有進行真實的加載操作。
設置啟動頁
給 app 添加啟動頁,這應該是最常見的實現偽加載的方式了。當應用啟動頁播放完成跳轉到首頁時,你能很明顯的感覺到,app 比沒有使用啟動頁之前變得更“流暢”了。
設置啟動頁參考文章 👉 Android—啟動頁+閃屏頁
其它啟動速度優化的方法:
1、盡量不要在Application
的onCreate
中寫初始化代碼
2、減少靜態類、靜態方法、靜態函數的使用,盡量做到用時再初始化
代碼優化
使用 adb 命令查看啟動 Activity 時間
在 Android 中,我們可以通過 adb
命令:adb shell am start -W packageName/packageName.ActivityName
獲取到啟動該 Activity
所消耗的時間,如下:
E:\Projects\StepDemo> adb shell am start -W com.binyouwei.demo/com.binyouwei.demo.MainActivityStarting: Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.binyouwei.demo/.MainActivity }
Status: ok
Activity: com.binyouwei.demo/.MainActivity
ThisTime: 522
TotalTime: 522
WaitTime: 525
Complete
在上方,我輸入了 adb shell am start -W com.binyouwei.demo/com.binyouwei.demo.MainActivity
,系統給我響應了一大串的字符,其中的含義如下:
ThisTime
:指定的 activity 啟動耗時。
TotalTime
:應用自身啟動耗時 = ThisTime
+ 應用 Application
等資源啟動時間
WaitTime
:系統啟動應用耗時 = TotalTime
+ 系統資源啟動時間
使用 Profile 查看 Activity 方法耗時,對其進行優化
使用參考文章👉Android Studio 中 CPU Profiler 系統性能分析工具的使用
WorkManager 后臺保活
使用 WorkManager
實現后臺保活,當應用處于后臺時,應用所占的內存不會被系統完全回收,再次啟動應用相較于第一次啟動會更快。
課外小知識
應用啟動狀態
冷啟動
冷啟動是指應用程序從頭開始啟動的過程,這意味著應用程序的進程被終止,用戶點擊應用圖標重新啟動應用。在冷啟動過程中,應用需要重新創建進程、初始化應用程序和加載 UI 界面。
溫啟動
溫啟動是指應用程序在后臺保持活動狀態并且重新進入前臺時的啟動方式。在溫啟動過程中,應用程序的進程仍然存在,但需要重新初始化和加載 UI 界面。
熱啟動
熱啟動是指應用程序在后臺保持活動狀態并且重新進入前臺時的快速啟動方式。在熱啟動過程中,應用程序的進程仍然存在,并且可以快速恢復到之前的狀態,而不需要重新初始化和加載 UI 界面。