深刻探索 Android 電量優化

前言

成爲一名優秀的Android開發,須要一份完備的知識體系,在這裏,讓咱們一塊兒成長爲本身所想的那樣~。

本文思惟導圖

1、正確認識

一、爲何要作電量優化?

在 Android 應用開發中,咱們須要考慮的是如何優化電量使用,讓咱們的 App 不會由於電量消耗太高被用戶排斥,或者被其餘安全應用報告,以此確保用戶黏性。html

二、電量重視度不夠

開發中一直鏈接手機,不知道電量消耗有多快。java

三、電量消耗線上難以量化

咱們沒有辦法拿到每個用戶手機的組件能耗,其中不一樣的硬件模塊使用了不一樣的參數,而後使用了不一樣的算法來進行估算。可是,具體的參數值根據手機所使用的硬件來講是不同的。python

2、電池技術

一、電池容量

如今通常手機的電池容量會佔用內部組件將近一半的空間。android

二、充電時間

1)、OPPO VOOC 閃充技術

  • 一、適配器中加入 MCU 智能芯片,得益於 MCU 對電流的精準調節,VOOC 實現了分段恆流和分檔技術,起步時,VOOC 會掛上高速檔,中間時會自動掛上中速檔,讓你快速前行,結尾時又會切換成低速擋,讓你平穩到站。
  • 二、從適配器到接口再到手機內部的全端式五重防禦技術。
    • 1)、適配器過載保護 電流進入適配器時,其中的傳感器會實時檢測電壓電流,安全時, MOSFET(保護)開關會自動打開閃充。
    • 2)、閃充條件鑑定保護 電流經過適配器時,MCU 芯片會識別設備是否支持閃充,只有支持纔開啓閃充與第二級過載保護。
    • 3)、接口過載保護 電流進入手機時,在特別定製的 7pinUSB 接口處,手機內的 MCU 會控制第三個 MOSFET(保護)開關,實行第三級過載保護。
    • 4)、電池過載保護 電池內的特殊 IC 和 MOSFET(保護)開關負責對進入電池的電壓電流實行過載保護。
    • 5)、電池熔絲保護 出現異常時,電池內的保險絲會當即熔斷,物理性斷絕電流輸入。
  • 三、將充電安全指數從 PPM(百萬分之一)提高至航天級別 DPM(十億分之一)。

2)、快充技術

P=UI(電功率=電壓 * 電流)git

普通充電過程

  • 1)、先將 220V 電壓經過充電頭降至 5V。
  • 2)、而後,手機內部電路再把 5V 電壓降至 4.2V。
  • 3)、最後,把電量輸送給電池,而整個降壓的過程當中會產生熱能。

分類

  • 1)、高壓低電流快充方案:在充電過程當中國提高充電電壓(7-20V)來提高充電功率。
  • 2)、低壓大電流快充方案:在電壓必定狀況下,增長電流,一般使用並聯電路的方式進行分流。

3)、鋁-石墨烯超級電池

  • 超高耐用性和安全性,快充充電1.1秒就能充滿電。
  • 實驗階段。

三、壽命

一般使用充電循環次數衡量。github

四、安全性

嚴格控制電池容量,例如 VOOC 就使用了各類安全檢測技術。web

五、電量和硬件

  • 手機耗電是經過使用相應的硬件模塊來消耗電能。
  • CPU、屏幕、WIFI、數據網絡、GPS、音視頻通話在平常耗電量中佔比最大。

六、Android 耗電演進

KITKAT

批處理傳感器

分批有效地收集和傳遞傳感器事件。算法

Alarm 對齊

批處理在合理的類似時間內的全部應用的鬧鈴,以便系統僅喚醒一次。docker

Lollipop

  • 開啓 Volta 項目
  • Job Scheduler
  • dumpsys batterystats
  • Battery Historian
  • 修復 native fork 進程保活的 bug

Marshmallow

  • 省電功能
  • Doze 低功耗模式
  • App Standby 應用待機摸手機

Nougat

  • 優化省電功能
  • Doze 增強版
  • implicit broadcasts 顯示
  • 混合編譯

Oreo

  • 更多優化省電功能
  • 後臺執行限制
  • 後臺位置限制

P(電壓管理嚴格限制)

應用待機分組(App Standby Bueckets)

  • 從應用安裝開始。
  • 分組決定後臺被限制的程度。
  • 不經常使用的應用將被限制地更加嚴格。

應用後臺限制(Background Restrictions)

  • 用戶開啓。
  • 中止後臺運行。
  • 提示用戶後臺耗電嚴重的應用,用戶可選擇中止它們的後臺運行。

省電模式(Battery Saver)

  • 用戶開啓。
  • 全部應用進入待機模式。
  • 更加嚴格的後臺限制,並且無視應用的 Target API。

3、電量檢測方案

對於電量的統計有一個公式,以下所示:shell

模塊電量(mAh) = 模塊電流(mA)* 模塊耗時(h)
複製代碼

Android 系統要求 ROM 廠商必須在 /frameworks/base/core/res/res/xml/power_profile.xml 提供組件的電源配置文件。而 Android 系統的電量計算 PowerProfile 正是經過讀取 power_profile.xml 的數據。

一、設置—耗電排行

  • 1)、直觀,但沒有詳細數據,對解決問題幫助不大。
  • 2)、須要找特定場景專項測試,好比在某一個界面操做一段時間,而後來判斷這個頁面是否耗電。

二、使用廣播監聽電量變化—ACTION_BATTERY_CHANGED

獲取電池電量、充電狀態、電池狀態等信息。

實戰案例

IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED); Intent intent = registerReceiver(null, filter); LogUtils.i("battery " + intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)); 複製代碼

缺點

  • 1)、價值不大:針對手機總體的耗電量,而非單個 App。
  • 2)、實時性差、精度較低,被動通知。

三、dumpsys batterystats

batterystats 是 Android 5.0 提供的工具,它能夠獲取各個 App 的 WakeLock、CPU 時間佔用等信息,同時增長了一個 Estimated power use(mAh)功能,預估耗電量。

做用

將電量測量轉化爲功能模塊的使用時間或者次數。

adb shell dumpsys batterystats > battery.txt
複製代碼

在 battery.txt 搜索 ‘Estimated power use’ 關鍵字,下面粗略統計了各個 Uid 的總耗電量。

Estimated power use (mAh): Capacity: 3350, Computed drain: 2767, actual drain: 3752-3853 Uid 1000: 1014 ( cpu=999 wake=1.36 radio=11.4 wifi=1.24 gps=0.435 sensor=0.808 ) Excluded from smearing Unaccounted: 985 ( ) Including smearing: 0 ( ) Excluded from smearing Uid 0: 416 ( cpu=157 wake=210 radio=38.8 wifi=9.51 ) Excluded from smearing ... 複製代碼

batterystats 所記錄的電量統計數據源自於 BatteryStatsService-電量統計服務,其實現類爲 BatteryStatsImpl,內部正是使用的 PowerProfile 。

BatteryStatsImpl 爲每個應用建立與之對應的 UID 來監控器系統資源的使用狀況,其統計了 12 大模塊的電量消耗,以下所示:

  • Camera、Audio、Video
  • Bluetooth、Network、Wakelock
  • Sensor、Radio、Screen
  • WIFI、CPU、GPS

四、Battery Historian

特色

  • 1)、查看自設備上次充電以來各類彙總統計信息,並且能夠選擇對應的 App 查看詳細信息。
  • 2)、可視化展現指標:
    • 耗電比例。
    • 執行時間、次數。
  • 3)、僅適合線下使用。

安裝

  • 1)、安裝 Docker
  • 2)、docker -- run -p :9999 gcr.io/android-battery-historian/stable:3.0 --port 9999 (須要外網)

導出電量信息

  • 1)、使用 batterystats 命令重置手機電量:adb shell dumpsys batterystats --reset
  • 2)、使用 batterystats 命令獲取電池數據權限並開啓記錄全面的電量信息:adb shell dumpsys batterystats --enable full-wake-history
  • 3)、測試完成後,使用 bugreport 導出電量信息:
    • 7.0和7.0之後:adb bugreport bugreport.zip
    • 6.0和6.0以前:adb bugreport > bugreport.txt
    • 經過 historian 圖形化展現結果:python historian.py -a bugreport.txt > battery.html

上傳分析

  • 1)、打開 http://localhost:

若是打不開,可使用備用網站 bathist

  • 2)、上傳 bugreport 文件,點 Submit 提交便可。

Battery Historian 數據分析

Hitorian V2 — 電量統計圖表

Add Metrics

在 Add Metrics 中咱們能夠增長更多的測量項。

CPU running

若是一直處於 running,則代表電量消耗比較高。

JobScheduler

選中 Job Scheduler 的某一個工做時間片,咱們能夠查看具體的 發生的時間、耗時以及次數,最重要的是它統計出來了是哪個進程在使用這個 JobScheduler。

App Selection

  • 1)、選擇要分析電量的指定 App。
  • 2)、點擊右邊區域的 System Stats 一欄能夠在下方查看各個系統組件的電量百分比消耗詳情,例如 Userspace Wakelocks。

主入口處的 Switch to Bugreport Comparison

選擇多個文件進行上傳對比。

五、電量專項測試

1)、耗電場景測試

  • 複雜計算。
  • 音視頻播放。

2)、傳感器相關

  • 使用時長
  • 耗電量
  • 發熱

3)、後臺靜默測試

4、耗電優化

一、耗電優化的難點

  • 1)、 缺少現場,沒法復現
  • 2)、 信息不全,難以定位
  • 3)、 沒法評估結果

在 App 開發中,常常會因爲某個需求場景或 代碼 bug 而致使大量耗電。

二、後臺調度任務省電

思考步驟

  • 須要後臺運行
    • 長時間下載:DownloadManager
    • 數據同步:SyncAdapter
    • 本地任務:JobScheduler
  • 特定時間執行:AlarmManager
  • 實時通訊:推送服務
  • 馬上執行:Foreground Service

對於耗電優化中,咱們最經常使用的就是 JobScheduler,下面👇,咱們來實戰一下。

Job Scheduler 實戰

/**  * 開啓 JobScheduler  */ private void startJobScheduler() {  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {  JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);  JobInfo.Builder builder = new JobInfo.Builder(1, new ComponentName(getPackageName(), JobSchedulerService.class.getName()));  // 設置僅在 充電和WIFI 下才使用 JobScheduler 進行批量任務處理  builder.setRequiresCharging(true)  .setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED);  jobScheduler.schedule(builder.build());  } } 複製代碼

其中,JobSchedulerService 就是用於進行批量任務處理的服務,示例代碼以下所示:

/**  * 用於進行批量任務處理的 JobSchedulerService  */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) public class JobSchedulerService extends JobService {   @Override  public boolean onStartJob(JobParameters params) {  // 此處執行在主線程  // 模擬一些處理:批量網絡請求,APM日誌上報  return false;  }   @Override  public boolean onStopJob(JobParameters params) {  return false;  } } 複製代碼

特色

  • 1)、 僅支持 API 21 及之上
  • 2)、 在符合某些條件時建立執行在後臺的任務
  • 3)、 把不緊急的任務放到更合適的時機批量處理

符合 Android 規則,手機在充電狀態纔去作耗電工做。示例代碼以下所示:

IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus = context.registerReceiver(null, ifilter); //獲取用戶是否在充電的狀態或者已經充滿電了 int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager.BATTERY_STATUS_FULL; 複製代碼

三、電量優化套路總結

一、優化應用的後臺耗電

避免後臺長時間獲取 WakeLock、WIFI 和藍牙的掃描等。

二、符合系統的耗電規則

Android P 使用了 Android Vitals 監控後臺耗電,其規則以下所示:

  • 1)、Alarm Manager wakeup 喚醒過多:當手機不在充電狀態,每小時 wakeup 喚醒次數大於 10 次。
  • 2)、頻繁使用局部喚醒鎖:當手機不在充電狀態,partial wake lock 持有超過1小時。
  • 3)、後臺網絡使用量太高:當手機不在充電狀態並且應用在後臺,每小時網絡使用量超過 50MB。
  • 4)、後臺 WiFi scans 過多:當手機不在充電狀態並且應用在後臺,每小時大於4次 WiFi scans。

三、CPU 時間片

Android 手機保護 AP 和 BP 兩個 CPU。AP 即 Application Processor,全部的用戶界面以及 App 都是運行在 AP 上的。BP 即 Baseband Processor,手機射頻都是運行在這個 CPU 上的。而通常咱們所說的耗電,PowerProfile 文件裏面的 CPU,指的是 AP

CPU 耗電一般有兩種狀況:

  • 1)、 長期頻繁喚醒:本來能夠僅僅在 BP 上運行,消耗 5mA 左右,可是由於喚醒,AP 就會運做,不一樣手機狀況不同,至少會致使 20~30 mA 左右的耗電
  • 2)、 CPU 長期高負荷:例如 App 退到後臺的時候沒有中止動畫,或者程序有不退出的死循環等等,致使 CPU 滿頻、滿核地跑

經常使用優化 CPU 時間片的方式有:

  • 1)、 獲取運行過程線程 CPU 消耗,定位 CPU 佔用率異常方法
  • 2)、 減小後臺應用的主動運行

四、網絡相關

一般狀況下,使用 WIFI 鏈接網絡時的功耗要低於使用移動網絡的功耗。而使用移動網絡傳輸數據,電量的消耗有如下3種狀態:

  • Full power:高功率狀態,移動網絡鏈接被激活,容許設備以最大的傳輸速率進行操做
  • Low power:低功耗狀態,對電量的消耗差很少是 Full power 狀態下的 50%
  • Standby:空閒態,沒有數據鏈接須要傳輸,電量消耗最少

所以,爲了不網絡鏈接所帶來的電量消耗,咱們能夠採用以下幾種方案:

  • 1)、儘可能在 WIFI 環境下進行數據傳輸,在使用 WIFI 傳輸數據時,應該儘量增大每一個包的大小(不超過 MTU),並下降發包的頻率。
  • 2)、在蜂窩移動網絡下須要對請求時機及次數控制:能夠延遲執行的網絡請求稍後一塊兒發送,最好作到批量執行,儘可能避免頻繁的間隔網絡請求,以儘可能多地保持在 Radio Standby 狀態。
  • 3)、使用 JSON 和 Protobuf 進行數據壓縮,減小時間。
  • 4)、禁止使用輪詢功能:輪詢會致使網絡請求一直處於被激活的狀態,耗電太高。

五、定位相關

  • 1)、 根據場景謹慎選擇定位模式:對定位準確度沒那麼高的場景能夠選擇低精度模式
  • 2)、 能夠考慮網絡定位代替 GPS
  • 3)、 使用後務必及時關閉,減小更新頻率,例如定位開啓必定時間後超過某個閾值能夠執行一個兜底策略:強制關閉 GPS

六、界面相關

  • 1)、 離開界面後中止相關活動,例如關閉動畫
  • 2)、 耗電操做判斷先後臺,若是是後臺則不執行相關操做

七、WakeLock 相關

WakeLock 經常使用於後臺播放音視頻、錄製音視頻、下載文件的狀況。若是沒有合理使用 WakeLock,則會形成嚴重的耗電問題,爲了不該問題,咱們應該按期針對使用了 WakeLock 的模塊進行重點排查

咱們可使用 adb shell dumpsys power 命令查看系統當前的耗電信息,其中咱們能夠看到 WakeLock 列表,它一般會以 」mLocks.size「 或者 」Wake Locks:size「 開頭。關於 WakeLock 的使用咱們要着重注意如下幾點:

  • 1)、 注意成對使用 acquire、release
  • 2)、 建議使用帶參數的 acquire,避免沒有及時釋放而致使電量消耗過大
  • 3)、 使用 finally 確保 release 必定會被調用
  • 4)、 常亮場景使用 keepScreenOn 便可
  • 5)、 WakeLock 有一個接口 setReferenceCounted,用來設置 WakeLock 的技術機制,官方默認爲計數。true 爲計數,false 爲不計數。所謂計數即每個 acquire 必須對應一個 release;不計數則是不管有多少個 acquire,一個 release 就能夠釋放。可是問題是有的第三方 ROM 它將默認設置爲了避免計數,覺得咱們須要在調用 newWakeLock 以後再調用 setReferenceCounted 爲 false

八、計算優化

浮點運算比整數運算更消耗 CPU 時間片,所以耗電也會增長。避開浮點運算的優化方法以下所示:

  • 1)、 除法變乘法
  • 2)、 充分利用移位
  • 3)、 在 native 層開發時,能夠利用 ARM neon 指令集作並行運算,注意須要 ARM V7 及以上架構 CPU 才能支持

九、滅屏時中止動畫

咱們能夠監聽滅屏以及亮屏的廣播,在滅屏的時候中止 surfaceView 的動畫繪製。在亮屏的時候,恢復動畫的繪製

5、耗電監控

之後臺耗電監控爲主,必須監控的模塊有:

  • 1)、 Alarm wakeup
  • 2)、 WakeLock
  • 3)、 WiFi scans
  • 4)、 Network

必須監控的現場信息有

  • 1)、 堆棧信息
  • 2)、 是否充電
  • 3)、 電量水平
  • 4)、 應用先後臺時間
  • 5)、 CPU 狀態信息

最後,咱們須要 提煉規則,將監控內容 => 抽象成規則

一、Java Hook

咱們能夠經過代理對應的 Service 實現,完成收集 Wakelock、Alarm、GPS 的申請堆棧、釋放信息、手機充電狀態等等。

示例項目

二、電量輔助監控實戰

1)、獲取運行時能耗文件

  • 1)、adb pull /system/framework/framework-res.apk
  • 2)、反編譯,xml—》power_profile

2)、電量輔助監控

線下使用 epic 進行 AOP 電量輔助統計

這裏咱們就以 WakeLock 的監控爲例,切面代碼以下所示:

public static long sStartTime = 0;
@Insert(value = "acquire") @TargetClass(value = "com.optimize.performance.wakelock.WakeLockUtils",scope = Scope.SELF) public static void acquire(Context context){  trace = Log.getStackTraceString(new Throwable());  sStartTime = System.currentTimeMillis();  Origin.callVoid();  new Handler().postDelayed(new Runnable() {  @Override  public void run() {  WakeLockUtils.release();  }  },1000); } @Insert(value = "release") @TargetClass(value = "com.optimize.performance.wakelock.WakeLockUtils",scope = Scope.SELF) public static void release(){  LogUtils.i("PowerManager "+(System.currentTimeMillis() - sStartTime)+"/n"+trace); 複製代碼

此外,咱們也能夠利用 epic 來監控每一個線程的執行時間,超過閾值則警告,示例代碼以下所示:

public static long runTime = 0;
@Insert(value = "run") @TargetClass(value = "java.lang.Runnable",scope = Scope.ALL) public void run(){  runTime = System.currentTimeMillis();  Origin.callVoid();  LogUtils.i("runTime "+(System.currentTimeMillis() - runTime)); } 複製代碼

三、編譯插樁

寫一個基礎類,而後在統一的調用接口中添加監控邏輯。這裏咱們能夠參考 Facebook Battery-Metrics 獲取、監控數據的方式。其代碼以下所示:

public class WakelockMetrics {
  /**  * 獲取 WakeLock  *  * @param wakeLock WakeLock  * @param timeout 超時時間  */  public static void acquire(PowerManager.WakeLock wakeLock, long timeout) {  wakeLock.acquire(timeout);  // 監控 wakelock 相關信息  Log.e("HOOOOOOOOK", "--acquireWakeLock--");  Log.e("HOOOOOOOOK", Utils.getStackTrace());  // 使用 Battery-Metrics 庫統計其它維度的電量信息   }   /**  * 釋放 WakeLock  *  * @param wakeLock WakeLock  */  public static void release(PowerManager.WakeLock wakeLock) {  wakeLock.release();  Log.e("HOOOOOOOOK", "--releaseWakeLock--");  Log.e("HOOOOOOOOK", Utils.getStackTrace());  // 使用 Battery-Metrics 庫統計其它維度的電量信息   }  } 複製代碼

Gradle 耗電量統計插件中 BatteryCreateMethodVisitor 的核心實現代碼以下所示:

@Override
public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {  // 監控 Wakelock  String monitorClass = "com/ss/android/ugc/bytex/example/battery_monitor/WakelockMetrics";  if (!monitorClass.equals(className)  && "android/os/PowerManager$WakeLock".equals(owner)  && opcode == Opcodes.INVOKEVIRTUAL  && "acquire".equals(name)) {  mv.visitMethodInsn(  Opcodes.INVOKESTATIC,  monitorClass,  name,  "(Landroid/os/PowerManager$WakeLock;J)V",  isInterface  );  return;  }  if (!monitorClass.equals(className)  && "android/os/PowerManager$WakeLock".equals(owner)  && opcode == Opcodes.INVOKEVIRTUAL  && "release".equals(name)) {  mv.visitMethodInsn(  Opcodes.INVOKESTATIC,  monitorClass,  name,  "(Landroid/os/PowerManager$WakeLock;)V",  isInterface  );  return;  }  // 監控 Gps  monitorClass = "com/ss/android/ugc/bytex/example/battery_monitor/GpsMetrics";  if (!monitorClass.equals(className)  && "android/location/LocationManager".equals(owner)  && opcode == Opcodes.INVOKEVIRTUAL  && "requestLocationUpdates".equals(name)) {  mv.visitMethodInsn(  Opcodes.INVOKESTATIC,  monitorClass,  name,  "(Landroid/location/LocationManager;Ljava/lang/String;JFLandroid/location/LocationListener;)V",  isInterface  );  return;  }  if (!monitorClass.equals(className)  && "android/location/LocationManager".equals(owner)  && opcode == Opcodes.INVOKEVIRTUAL  && "removeUpdates".equals(name)) {  mv.visitMethodInsn(  Opcodes.INVOKESTATIC,  monitorClass,  name,  "(Landroid/location/LocationManager;Landroid/location/LocationListener;)V",  isInterface  );  return;  }  // 監控 Alarm Service  monitorClass = "com/ss/android/ugc/bytex/example/battery_monitor/AlarmMetrics";  if (!monitorClass.equals(className)  && "android/app/AlarmManager".equals(owner)  && opcode == Opcodes.INVOKEVIRTUAL  && "set".equals(name)) {  mv.visitMethodInsn(  Opcodes.INVOKESTATIC,  monitorClass,  name,  "(Landroid/app/AlarmManager;IJLandroid/app/PendingIntent;)V",  isInterface  );  return;  }  if (!monitorClass.equals(className)  && "android/app/AlarmManager".equals(owner)  && opcode == Opcodes.INVOKEVIRTUAL  && "cancel".equals(name)) {  mv.visitMethodInsn(  Opcodes.INVOKESTATIC,  monitorClass,  name,  "(Landroid/app/AlarmManager;Landroid/app/PendingIntent;)V",  isInterface  );  return;  }  super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); } 複製代碼

缺點

系統的代碼插樁方案沒法替換。

6、電量優化常見問題

一、怎麼作電量測試?

電量相關的測試相對來講難度較大,由於 App 在具體手機上的耗電量沒法準確統計,每個手機所使用的硬件不同,那麼它相應的功耗就不同。並且這個功耗值咱們只能在線下經過導出手機的 power_profile.xml 文件拿到。

因爲咱們沒法獲取準確的耗電量,因此咱們只能增長多個維度來輔助判斷 App 是否耗電。

最後,咱們能夠分場景各個突破。

關於電量測試,咱們能夠針對各個功能場景進行鍼對性的專項測試。操做一段時間後,咱們能夠在手機設置—電量消耗裏面,利用其數據做爲判斷依據。這樣雖然直觀,但精確度不行。

介紹 Battery Historian:

  • Google 推出的一款 Android 電量分析工具,它支持 Android 5.0 及以上系統的電量分析。
  • 它獲取到的各個耗電模塊的耗電信息要相對精確、豐富地多。例如 GPS、WaleLock、藍牙 等的工做時間以及耗電量。
  • 此外,它不只能夠針對單個 App 進行選擇,也能夠比對不一樣的電量場景的信息,好比 優化前、優化後 的信息。
  • Battery Historian 的缺點在於它只能在線下使用。所以除了使用其在線下測試以外,咱們還須要在線上增長一些電量的輔助監控,統計例如:耗電組件的使用次數、調用堆棧以及訪問時間。這些都是與用戶相關的基礎電量消耗數據,若是有用戶反饋,咱們就能夠經過這些信息來判斷用戶是否是有耗電的操做。

二、有哪些有效的電量優化手段?

由於咱們不能在線上統計出 App 的電量消耗,所以須要在儘可能保證 App 在正常使用下的耗電。對此咱們採起了一系列的電量優化措施:

1)、網絡相關

  • 網絡請求的時機以及次數,將能夠延遲的網絡請求批量發送,減小網絡被激活的時機與次數。
  • 此外,咱們能夠對網絡傳輸數據進行壓縮,以下降傳輸的時間與流量。
  • 最後,必定要禁止使用輪詢的方式來作業務操做。

2)、傳感器相關

根據場景謹慎地選擇傳感器使用的模式,好比說在使用 GPS 的時候通常要避免使用高精度的模式,或者是儘可能複用上一次的定位結果。

3)、WakeLock

咱們在實際項目中使用 WakeLock 有幾個注意事項,第一,acquire、release 要成對地釋放,第二,儘可能使用 acquire 的超時方法來設置超時時間,避免由於異常狀況從而致使 WakeLock 而沒法釋放的狀況,第三,關於 WakeLock 的釋放必定要寫在 try-catch-finally 的 finally 當中,保證 WakeLock 在異常狀況下的釋放。

4)、JobScheduler

JobScheduler 能夠容許開發者在符合某些條件下創造執行在後臺的任務,咱們能夠設置執行一些耗電操做的場景,好比說 處於 WIFI 狀態下同時鏈接電源 的狀況下。同時,要注意用戶在離開界面後,要避免耗電的操做,好比說中止播放動畫。經過這些操做,咱們的 App 就不會比以前耗電了。

7、總結

對於電量優化來講,最重要的就是 創建監控與自動化報警的一整套體系,只有發現了耗電的問題所在,才能使用針對性的解決措施

公衆號

個人公衆號 JsonChao 開通啦,歡迎關注~

參考連接:


Contanct Me

● 微信:

歡迎關注個人微信:bcce5360

● 微信羣:

因爲微信羣人數過多,麻煩你們想進微信羣的朋友們,加我微信拉你進羣。

● QQ羣:

2千人QQ羣,Awesome-Android學習交流羣,QQ羣號:959936182, 歡迎你們加入~

About me

很感謝您閱讀這篇文章,但願您能將它分享給您的朋友或技術羣,這對我意義重大。

但願咱們能成爲朋友,在 Github掘金上一塊兒分享知識。

相關文章
相關標籤/搜索