Android電量優化全解析

本文已同步發表到個人微信公衆號,掃一掃文章底部的二維碼或在微信搜索 「程序員驛站」便可關注,天天都會更新優質技術文章。python

電量優化一直是個老生常談的話題,關於這塊的文章已經有不少了,最近也在作這塊東西,因此結合本身的理解寫下這篇文章。好了開始咱們今天的正題,關於這塊的論述我按照下述結構進行。 在這裏插入圖片描述android

電量消耗的全過程分析

手機設備會執行各類任務和各類複雜計算,如秀自拍圖片上傳朋友圈、秀直播等等,爲了完成這些設備硬件會快速消耗手機電池電量。很明顯,任務處理的越複雜,電量就會消耗的越多和越快,一眨眼的功夫電量就消耗完了,這個時候用戶的手機頓時變成個累贅的磚頭了,用戶就會懷疑誰(哪一個app)這麼耗電,而後把它卸了!git

寫出耗電量低的應用的關鍵是要透徹理解它的所有過程。程序員

在這裏插入圖片描述

在電子編程世界,這種硬件消耗電量 來執行任務的過程,叫作超時電流消耗,任何電子編程專業的人都會告訴你,你的設備的各項活動在相同時間內,消耗的電量是不一樣的。github

好比,不少手機號稱待機好幾天,這個確實是真的,不過就是使用飛行模式放在家裏什麼都不幹,確實能夠甚至能夠堅持10多天。可是咱們一旦使用它,好比使用蜂窩式無線數據交換(3G4G)、屏幕保持喚醒狀態等,手機電量就會很快被消耗掉。golang

做爲開發者,咱們很想知道個人應用執行的哪些任務消耗的電量是最多的?這個問題確實會很棘手。由於電量消耗的計算與統計是一件麻煩並且矛盾的事情,記錄電量消耗自己也是一個費電量的事情(因此不少設備都把這個監測電量的功能閹割掉了)。docker

惟一可行的方案是使用第三方監測電量的設備,這樣纔可以獲取到真實的電量消耗(由於第三方硬件監測的時候是用的本身的供電而不是用的手機的電量)。shell

耗電狀況,例如:打開屏幕,全部要使用CPU/GPU工做的動做都會喚醒屏幕,都會消耗電量。這和應用程序喚醒設備還不同。好比使用叫醒鬧鐘(wake clock)、AlarmManager、JobSchedulerAPI。
在這裏插入圖片描述編程

手機哪些地方最耗電?

喚醒屏幕

當用戶點亮屏幕的時候,意味着系統的各組件要開始進行工做,界面也須要開始執行渲染。服務器

待機狀態的電量消耗:
在這裏插入圖片描述

使用和喚醒屏幕後:
在這裏插入圖片描述

當設備從休眠狀態中,被應用程序喚醒時,能夠看到在第一次喚醒時,出現一條電量使用高峯線。

CPU喚醒使用

CUP 喚醒時的高峯線:
在這裏插入圖片描述

接下來就是後續的一些執行的消耗了:
在這裏插入圖片描述

當工做完成後,設備會主動進行休眠,這很是重要,在不使用或者不多使用的狀況下,長時間 保持屏幕喚醒會迅速消耗電池的電量。

蜂窩式無線

當設備經過無線網發送數據的時候,爲了使用硬件,這裏會出現一個喚醒耗電高峯。接下來還 有一個高數值,這是發送數據包消耗的電量,而後接受數據包也會消耗大量電量 也看到一個峯值。
在這裏插入圖片描述

一般狀況下,使用3G移動網絡傳輸數據,電量的消耗有三種狀態:

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

Battery-Historian 電量分析工具的使用

要進行電量優化,咱們首先得知道電都消耗到哪裏去了,咱們能夠經過 google 開源的 Battery-Historian 來進行分析。

工具開源地址: https://github.com/google/battery-historian

Battery History 工具安裝

根據 gitbub 上面介紹,Battery History
工具的安裝有兩種方式:

方式1: 經過安裝 Docker 環境來安裝。(這種方式很簡單,Docker 真心好用)

  1. 按照 Docker 網站上的說明安裝 Docker Community Edition。
  2. 使用如下命令運行 Battery Historian 鏡像:
docker --run -p port_number:9999 gcr.io/android-battery-historian:2.1 --port 9999

方式2 經過編譯 gitbub 上面的源碼來安裝。

  1. GO 環境安裝:具體能夠參考 Mac os 安裝 golang 開發環境(https://www.jianshu.com/p/79bdd20c46cf)
  2. 安裝 git.
  3. 安裝 Python。僅支持 python2.7 (https://www.python.org/ )
  4. 安裝Java環境

下載 Battery Historian 源碼而且運行

輸入以下命令行 下載到GOPATH 配置目錄下。

go get -d -u github.com/google/battery-historian/...

在這裏插入圖片描述

進入到$GOPATH/src/github.com/google/battery-historian目錄下方

cd $GOPATH/src/github.com/google/battery-historian

在這裏插入圖片描述

運行 Battery Historian
1.執行命令:

go run setup.go

Compile Javascript files using the Closure compiler
在這裏插入圖片描述
2.接着在執行命令:

go run cmd/battery-historian/battery-historian.go [--port <default:9999>]

Run Historian on your machine (make sure $PATH contains $GOBIN)
3.登陸網址http://localhost:9999查看battery-historian是否運行。

到此Battery-historian的環境就整好了。

電量數據收集

Android 5.0 及以上的設備, 容許咱們經過 adb 命令 dump 出電量使用統計信息。
1.由於電量統計數據是持續的, 會很是大, 統計待測試的 App 以前須要連上設備,所以須要reset(重置)電池數據收集。命令行執行:

$ adb shell dumpsys batterystats --resetBattery stats reset

2.斷開usb鏈接的測試設備, 操做要測試的App。

3.從新鏈接設備, 使用 adb 命令導出相關統計數據:

  • Android 7.0 及以上執行以下命令:
adb bugreport > [path/]bugreport.zip
  • Android 5.0/ 6.0執行以下命令:
adb bugreport > [path/]bugreport.txt

導出的統計數據存儲到 bugreport.zip(bugreport.txt), 藉助 battery-historian 工具來圖形化 展現電池的消耗狀況.

上傳 bugreport.zip(bugreport.txt)文件至 http://localhost:9999
在這裏插入圖片描述

battery-historian電量分析結果:
在這裏插入圖片描述

分析指標

下圖是使用 adb 命令將採集的電量數據上傳至 Battery Historian 而獲得電量的分析狀況。(咱們能夠經過包名過濾具體應用的耗電狀況)

在這裏插入圖片描述

各指標的含義

  • 橫座標: 橫座標就是一個時間範圍,我們的例子中統計的數據是以重置爲起點,獲取 bugreport 內容時 刻爲終點。咱們一共採集了多長時間的數據;
  • 縱座標: 關鍵數據點說明以下。
數據項 說明
battery_level 電量,能夠看出電量的變化
plugged 充電狀態,這一欄顯示是否進行了充電,以及充電的時間範圍
screen 屏幕是否點亮,這一點能夠考慮到睡眠狀態和點亮狀態下電量的使用信息
top 該欄顯示當前時刻哪一個 app 處於最上層,就是當前手機運行的 app,用來判斷某個 app 對手機電量的影響,這樣也能判斷出該 app 的耗電量信息。該欄記錄了應用在某 一個時刻啓動,以及運行的時間,這對咱們比對不一樣應用對性能的影響有很大的幫助
wake_lock wake_lock 該屬性是記錄 wake_lock 模塊的工做時間。是否有中止的時候等
running 界面的狀態,主要判斷是否處於 idle 的狀態。用來判斷無操做狀態下電量的消耗
Job 後臺的工做,好比服務 service 的運行
data_conn 數據鏈接方式的改變,上面的 edge 是說明採用的 gprs 的方式鏈接網絡的。此數據可 以看出手機是使用 2g,3g,4g 仍是 wifi 進行數據交換的。這一欄能夠看出不一樣的連 接方式對電量使用的影響
status 電池狀態信息,有充電,放電,未充電,已充滿,未知等不一樣狀態
phone_signal_strength 手機信號狀態的改變。 這一欄記錄手機信號的強弱變化圖,依次來判斷手機信號對電 量的影響
health 電池健康狀態的信息,這個信息必定程度上反映了這塊電池使用了多長時間
plug 充電方式,usb 或者插座,以及顯示鏈接的時間
Sync 是否跟後臺同步
phone_in_call 是否進行通話
gps gps 是否開啓

如何進行電量優化?

瞭解手機關鍵耗電的地方及分析耗電的工具後。接下來就是咱們的核心,如何來進行電量的優 化?首先咱們先簡單總結匯總一下耗電的相關因素

  • 屏幕亮暗相關
  • 設備 awake,sleep 的切換,尤爲是喚醒.
  • CPU 運行相關
  • 網絡
  • 傳感器

咱們都知道屏幕的渲染及 CPU 的運行是耗電的主要因素之一。因此當咱們在作內存優化、渲染優化、計算優化的時候,就已然在作電量優化。因此在平時的開發中,咱們要注意點滴性能 的優化積累,實際上當咱們來作電量分析的時候,也是在找本身挖的坑。因此儘可能有意識在項 目的開發過程當中儘可能少挖坑,這一點是咱們在分析其餘優化項首先要提到的一個點。

監聽手機充電狀態

咱們能夠經過下面的代碼來獲取手機的當前充電狀態:
在這裏插入圖片描述
獲得充電狀態信息以後,咱們能夠有針對性的對部分代碼作優化。好比咱們能夠判斷只有當前 手機爲 AC 充電狀態時 纔去執行一些很是耗電的操做。能夠經過下面的方法判斷手機當前的充 電狀態。
在這裏插入圖片描述

這裏咱們就須要思考,根據具體的業務,考慮將一些不須要及時地和用戶交互的操做放到充電 的時候去作。好比:360 手機助手,當充上電的時候,纔會自動清理手機垃圾,自動備份上傳圖片、聯繫人 等到雲端,從而避免當用戶手機低電量時,任然繼續進行耗電操做。

屏幕喚醒

當 Android 設備空閒時,屏幕會變暗,而後關閉屏幕,最後會中止 CPU 的運行,這樣能夠防 止電池電量掉的快。但有些時候咱們須要改變 Android 系統默認的這種狀態:好比玩遊戲時我 們須要保持屏幕常亮,好比一些下載操做不須要屏幕常亮但須要 CPU 一直運行直到任務完成。

保持屏幕常亮比較好的方式是在 Activity 中使用 FLAG_KEEP_SCREEN_ON 的 Flag。
在這裏插入圖片描述

這個方法的好處是不像喚醒鎖(wake locks),須要一些特定的權限(permission)。而且能 正確管理不一樣 app 之間的切換,不用擔憂無用資源的釋放問題。

另外一個方式是在佈局文件中使用 android:keepScreenOn 屬性:
在這裏插入圖片描述

android:keepScreenOn = 「true」的做用和 FLAG_KEEP_SCREEN_ON 同樣,使用代碼的好 處是你容許你在須要的地方關閉屏幕。

注意:通常不須要人爲的去掉 FLAG_KEEP_SCREEN_ON 的 flag,windowManager 會管理好程序進入 後臺回到前臺的的操做。若是確實須要手動清掉常亮的 flag,使用
在這裏插入圖片描述

因此這裏咱們須要根據本身的 APP 實際狀況,根據業務來控制好是否保持屏幕常量。好比 APP 須要支持視頻播放。那麼在播放的界面須要控制好不熄屏,當退出播放時,固然就沒有了 這個設置。

WakeLock

wake_lock 鎖主要是相對系統的休眠而言的,意思就是程序給 CPU 加了這個鎖那系統就不會 休眠了,這樣作的目的是爲了全力配合咱們程序的運行。有的狀況若是不這麼作就會出現一些 問題。
須要使用 PowerManager 這個系統服務的喚醒鎖(wake locks)特徵來保持 CPU 處於喚醒狀 態。喚醒鎖容許程序控制宿主設備的電量狀態,建立和持有喚醒鎖對電池的續航有較大的影 響,因此,除非是真的須要喚醒鎖完成儘量短的時間在後臺完成的任務時才使用它。好比在 Acitivity 中就不必用了。若是須要關閉屏幕,使用上述的 FLAG_KEEP_SCREEN_ON。

只有一種合理的使用場景,使用後臺服務在屏幕關閉狀況下 hold 住 CPU 完成一些工做,須要 使用喚醒鎖,若是不使用喚醒鎖來執行後臺服務,不能保證因 CPU 休眠將來的某個時刻任務 會中止,這不是咱們想要的。

喚醒鎖可劃分並識別爲四種用戶喚醒鎖:

標記值 CPU 屏幕 鍵盤
PARTIAL_WAKE_LOCK 開啓 關閉 關閉
SCREEN_DIM_WAKE_LOCK 開啓 變暗 關閉
SCREEN_BRIGHT_WAKE_LOCK 開啓 變亮 關閉
FULL_WAKE_LOCK 開啓 變亮 變亮

注意:自 API 等級 17 開始,FULL_WAKE_LOCK 將被棄用。 應用應使用 FLAG_KEEP_SCREEN_ON。

1.添加喚醒鎖權限:

在這裏插入圖片描述

2.直接使用喚醒鎖:

在這裏插入圖片描述

注意:在使用該類的時候,必須保證 acquire 和 release 是成對出現的。否則當咱們業務已經不須要時, 當 CPU 處於喚醒狀態,這個時候就會損耗多餘的電量。

JobScheduler

自 Android 5.0 發佈以來,JobScheduler 已成爲執行後臺工做的很好的方式,其工做方式有 利於用戶在適當的時機執行正確的事情。應用能夠在安排做業的同時容許系統基於內存、電源 和鏈接狀況進行優化。JobSchedule 的宗旨就是把一些不是特別緊急的任務放到更合適的時機 批量處理。這樣作有兩個好處:

  • 避免頻繁的喚醒硬件模塊,形成沒必要要的電量消耗。
  • 避免在不合適的時間(例如低電量狀況下、弱網絡或者移動網絡狀況下的)執行過多的
    任務消耗電量。

GPS

選擇合適的 Location Provider

Android 系統支持多個 Location Provider:

  • GPS_PROVIDER: GPS 定位,利用 GPS 芯片經過衛星得到本身的位置信息。定位精準度高,通常在 10 米左右, 耗電量大;可是在室內,GPS 定位基本沒用。
  • NETWORK_PROVIDER: 網絡定位,利用手機基站和 WIFI 節點的地址來大體定位位置,這種定位方式取決於服務器,
    即取決於將基站或 WIF 節點信息翻譯成位置信息的服務器的能力。
  • PASSIVE_PROVIDER: 被動定位,就是用現成的,當其餘應用使用定位更新了定位信息,系統會保存下來,該應用接 收到消息後直接讀取就能夠了。

若是 App 只是須要一個粗略的定位那麼就不須要使用 GPS 進行定位,既耗費電量,定位的耗 時也久。

及時註銷定位監聽

在獲取到定位以後或者程序處於後臺時,註銷定位監聽,此時監聽 GPS 傳感器至關於執行 no- op(無操做指令),用戶不會有感知可是卻耗電。

多模塊使用定位儘可能復

多個模塊使用定位,儘可能複用上一次的結果,而不是都從新走定位的過程,節省電量損耗;例 如:在應用啓動的時候獲取一次定位,保存結果,以後再用到定位的地方都直接去取。

傳感器

使用傳感器,選擇合適的採樣率,越高的採樣率類型則越費電。

  • SENSOR_DELAY_NOMAL (200000 微秒)
  • SENSOR_DELAY_UI (60000 微秒)
  • SENSOR_DELAY_GAME (20000 微秒)
  • SENSOR_DELAY_FASTEST (0 微秒)

在後臺時注意及時註銷傳感器監聽

Doze and App Standby

最後提這一點,理論上不是電量優化,而是作電量優化要注意的一個坑。Doze and App Standby 是 Android 6.0 之後,提供了兩種省電延長電池壽命的功能。
具體可參考 google 官方介紹文檔。

參考資料:https://github.com/google/battery-historian#wakelock-analysis

關注個人技術公衆號"程序員驛站",天天都有優質技術文章推送,微信掃一掃下方二維碼便可關注:

相關文章
相關標籤/搜索