CPU 與網絡等是屬於 Background Process,若要優化,須要設法減小、延遲、合併 Background Process。html
從 API 23 開始, Android 提供了這兩種模式以延長電池壽命,是 Android 系統的大方針。Doze 就是將一些 Wakelocks、網絡、Jobs/Syncs、Alarms、GPS/Wifi 禁止/延遲,僅在須要喚醒這些東西時即到維護窗口時才喚醒。App Standby 是應用級別的,細分到每個應用中的,應用未使用一段時間後(即沒有 foreground process 時)就會進入 App Standby,進入此狀態後 App 就不能訪問網絡而且 Jobs/Syncs 都會受到延遲。java
固然,啓用 Foreground Service 就不會受到 Doze 和 App Standby 的影響。同時,在 AOSP 中這兩個模式是關閉的,具體須要看看手機廠商有沒有開啓,提起這個只是給到你們一個官方的方案來引導咱們作本身的方案。android
developer.android.google.cn/training/mo…git
若要進行功耗優化,則須要設法減小、延遲、合併 Background Process。經過 Doze 則是對 Background Process 進行合併,即合併到維護窗口時;經過 App Standby 則是對 Backgroud Process 進行延遲,即延遲到"使用"狀態下或充電狀態下。這些是系統級別的優化,而應用級別的優化則是在平時的積累中進行的,好比對耗電功能進行優化,原則上與上面一致,即減小、延遲、合併這些功耗大的功能:github
/** * This method checks for power by comparing the current battery state against all possible * plugged in states. In this case, a device may be considered plugged in either by USB, AC, or * wireless charge. (Wireless charge was introduced in API Level 17.) */
private boolean checkForPower() {
// It is very easy to subscribe to changes to the battery state, but you can get the current
// state by simply passing null in as your receiver. Nifty, isn't that?
IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = this.registerReceiver(null, filter);
// There are currently three ways a device can be plugged in. We should check them all.
int chargePlug = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = (chargePlug == BatteryManager.BATTERY_PLUGGED_USB);
boolean acCharge = (chargePlug == BatteryManager.BATTERY_PLUGGED_AC);
boolean wirelessCharge = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
wirelessCharge = (chargePlug == BatteryManager.BATTERY_PLUGGED_WIRELESS);
}
return (usbCharge || acCharge || wirelessCharge);
}
複製代碼
Battery Historian 是 Android 5.0 以後引入的一個獲取設備電量消耗信息的圖形化工具,可以直觀展現手機電量消耗。網絡
Battery_Historian_Tool使用說明數據結構
JobScheduler:系統利用這些觸發的設置,合併相同的 background process,從而優化內存和電池性能。併發
除避免內存泄漏外還有其餘內存優化手段:less
用 JobScheduler 替代 Service。若必須使用 Service,最好用 IntentService 限制服務壽命,全部請求完成後會自動中止。ide
使用 SparseArray、SparseBooleanArray、LongSparseArray 代替 HashMap 等數據結構。
必要時釋放內存:
import android.content.ComponentCallbacks2;
public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 {
/** * 當UI不可見時或系統資源不足時釋放內存 * @param level 引起的與內存相關的事件 */
public void onTrimMemory(int level) {
// 肯定引起了哪一個生命週期或系統事件
switch (level) {
case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
/* 釋放一些不必的內存資源。如今用戶界面已移至後臺 */
break;
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
/* 釋放應用不須要的內存。 應用程序運行時,設備內存不足。 引起的事件表示與內存相關的事件的嚴重性。 若是事件是TRIM_MEMORY_RUNNING_CRITICAL,那麼系統將開始殺死後臺進程。 */
break;
case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
/* 釋放盡量多的內存。 該應用程序位於LRU列表中而且系統內存不足。 引起的事件代表應用程序位於LRU列表中的位置。 若是引起的事件是 TRIM_MEMORY_COMPLETE, 這一進程將是最早終止的進程之一。 */
break;
default:
/* 釋聽任何非關鍵數據結構。 應用程序從系統接收到一個沒法識別的內存級別值。 將其視爲通常的低內存消息。 */
break;
}
}
}
複製代碼
檢查當前使用了多少內存,作好保護去釋放一些次要資源以防 OOM:
public void doSomethingMemoryIntensive() {
// 在作一些須要大量內存的事情以前檢查設備是否處於低內存狀態
ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();
if (!memoryInfo.lowMemory) {
// 當前處於低內存狀態 ...
}
}
// 獲取 MemoryInfo
private ActivityManager.MemoryInfo getAvailableMemory() {
ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
activityManager.getMemoryInfo(memoryInfo);
return memoryInfo;
}
複製代碼
優化佈局層次、避免自定義組件中 onDraw 建立大量臨時對象。