記憶體最佳化技巧
1 .謹慎使用 Service
讓一個沒用的 Service 在後臺執行對於一個應用的記憶體管理來說是一件最糟糕的事情。
要在 Service 的任務完成後停止它,不然 Service 佔用的這塊記憶體會洩漏。
當你的應用中執行著一個 Service,除非系統記憶體不足,否則它不會被幹掉。
這就導致對於系統來說 Service 的執行成本很高,因為 Service 佔用的記憶體其他的程序是不能使用的。
Android 有一個快取程序列表,當可用記憶體減少時,這個列表也會隨之縮小,這就會導致應用間的切換變得很慢。
如果我們是用 Service 監聽一些系統廣播,可以考慮使用 JobScheduler。
如果你真的要用 Service,可以考慮使用 IntentService,IntentService 是 Service 的一個子類,在它的內部有一個工作執行緒來處理耗時任務,當任務執行完後,IntentService 就會自動停止。
2. 選擇最佳化後的資料容器
Java 提供的部分資料容器並不適合 Android,比如 HashMap,HashMap 需要中儲存每一個鍵值對都需要一個額外的 Entry 物件。
Android 提供了幾個最佳化後的資料容器,包括 SparseArray、SparseBooleanArray 以及 LongSparseArray。
SparseArray 之所以更高效,是因為它的設計是隻能使用整型作為 key,這樣就避免了自動裝箱的開銷。
3 .小心程式碼抽象
抽象可以最佳化程式碼的靈活性和可維護性,但是抽象也會帶來其他成本。
抽象會導致更多的程式碼需要被執行,也就是需要更多的時間和把更多的程式碼對映到記憶體中。
如果某段抽象程式碼帶來的好處不大,比如一個地方可以直接實現而不需要用到介面的,那就不用介面。
4. 使用 protobuf 作為序列化資料
Protocol buffers 是 Google 設計的,它可以對結構化的資料序列化,與 XML 類似,不過比 XML 更小,更快,而且更簡單。
如果你決定使用 protobuf 作為序列化資料格式,那在客戶端程式碼中應該使用輕量級的 protobuf。
因為一般的 protobuf 會生成冗長的程式碼,這樣會導致記憶體增加、APK 大小增加,執行速度變慢等問題。
更多關於 protobuf 的資訊可以檢視 protobuf readme 中的 “輕量級版本” 。
5. Apk 瘦身
有些資源和第三方庫會在我們不知情的情況下大量消耗記憶體。
Bitmap 大小、資源、動畫以及第三方庫會影響到 APK 的大小,Android Studio 提供了 R8 和 ProGuard 幫助我們縮小 Apk,去掉不必要的資源。
如果你使用的 Android Studio 版本是 3.3 以下的,可以使用 ProGuard,3.3 及以上版本的可以使用 R8。
6. 使用 Dagger2 進行依賴注入
依賴注入框架不僅可以簡化我們的程式碼,而且能讓我們在測試程式碼的時候更方便。
如果我們想在應用中使用依賴注入,可以考慮使用 Dagger2。
Dagger2 是在編譯期生成程式碼,而不是用反射實現的,這樣就避免了反射帶來的記憶體開銷,而是在編譯期生成程式碼,
7. 謹慎使用第三方庫
當你決定使用一個不是為移動平臺設計的第三方庫時,你需要對它進行最佳化,讓它能更好地在移動裝置上執行。
這些第三方庫包括日誌、分析、圖片載入、快取以及其他框架,都有可能帶來效能問題。
記憶體最佳化技巧
1 .謹慎使用 Service
讓一個沒用的 Service 在後臺執行對於一個應用的記憶體管理來說是一件最糟糕的事情。
要在 Service 的任務完成後停止它,不然 Service 佔用的這塊記憶體會洩漏。
當你的應用中執行著一個 Service,除非系統記憶體不足,否則它不會被幹掉。
這就導致對於系統來說 Service 的執行成本很高,因為 Service 佔用的記憶體其他的程序是不能使用的。
Android 有一個快取程序列表,當可用記憶體減少時,這個列表也會隨之縮小,這就會導致應用間的切換變得很慢。
如果我們是用 Service 監聽一些系統廣播,可以考慮使用 JobScheduler。
如果你真的要用 Service,可以考慮使用 IntentService,IntentService 是 Service 的一個子類,在它的內部有一個工作執行緒來處理耗時任務,當任務執行完後,IntentService 就會自動停止。
2. 選擇最佳化後的資料容器
Java 提供的部分資料容器並不適合 Android,比如 HashMap,HashMap 需要中儲存每一個鍵值對都需要一個額外的 Entry 物件。
Android 提供了幾個最佳化後的資料容器,包括 SparseArray、SparseBooleanArray 以及 LongSparseArray。
SparseArray 之所以更高效,是因為它的設計是隻能使用整型作為 key,這樣就避免了自動裝箱的開銷。
3 .小心程式碼抽象
抽象可以最佳化程式碼的靈活性和可維護性,但是抽象也會帶來其他成本。
抽象會導致更多的程式碼需要被執行,也就是需要更多的時間和把更多的程式碼對映到記憶體中。
如果某段抽象程式碼帶來的好處不大,比如一個地方可以直接實現而不需要用到介面的,那就不用介面。
4. 使用 protobuf 作為序列化資料
Protocol buffers 是 Google 設計的,它可以對結構化的資料序列化,與 XML 類似,不過比 XML 更小,更快,而且更簡單。
如果你決定使用 protobuf 作為序列化資料格式,那在客戶端程式碼中應該使用輕量級的 protobuf。
因為一般的 protobuf 會生成冗長的程式碼,這樣會導致記憶體增加、APK 大小增加,執行速度變慢等問題。
更多關於 protobuf 的資訊可以檢視 protobuf readme 中的 “輕量級版本” 。
5. Apk 瘦身
有些資源和第三方庫會在我們不知情的情況下大量消耗記憶體。
Bitmap 大小、資源、動畫以及第三方庫會影響到 APK 的大小,Android Studio 提供了 R8 和 ProGuard 幫助我們縮小 Apk,去掉不必要的資源。
如果你使用的 Android Studio 版本是 3.3 以下的,可以使用 ProGuard,3.3 及以上版本的可以使用 R8。
6. 使用 Dagger2 進行依賴注入
依賴注入框架不僅可以簡化我們的程式碼,而且能讓我們在測試程式碼的時候更方便。
如果我們想在應用中使用依賴注入,可以考慮使用 Dagger2。
Dagger2 是在編譯期生成程式碼,而不是用反射實現的,這樣就避免了反射帶來的記憶體開銷,而是在編譯期生成程式碼,
7. 謹慎使用第三方庫
當你決定使用一個不是為移動平臺設計的第三方庫時,你需要對它進行最佳化,讓它能更好地在移動裝置上執行。
這些第三方庫包括日誌、分析、圖片載入、快取以及其他框架,都有可能帶來效能問題。