電量消耗的計算與統(tǒng)計是一件麻煩而且矛盾的事情,記錄電量消耗本身也是一個費電量的事情,隨著Android開的性能要求越來越高,電量的優(yōu)化,也顯得格外重要,一個耗電的應用,用戶肯定會毫不猶豫的進行卸載,所以本篇博客,我們一起來學習android性能優(yōu)化之電量優(yōu)化。
耗電情況,例如:打開屏幕,所有要使用CPU/GPU工作的動作都會喚醒屏幕,都會消耗電量。這和應用程序喚醒設備還不一樣。
(1)喚醒屏幕
當用戶電量屏幕的時候,意味著系統(tǒng)的各組件要開始進行工作,界面也需要開始執(zhí)行渲染。
待機狀態(tài)的電量消耗:
使用和喚醒屏幕后:
當設備從休眠狀態(tài)中,被應用程序喚醒時,就會產(chǎn)生一條電量使用高峰線。
當工作完成后,設備會主動進行休眠,這非常重要,在不使用或者很少使用的情況下,長時間保持屏幕喚醒會迅速消耗電池的電量。
(2)蜂窩式無線
通過這張圖,我們知道通過使用蜂窩無線時,會產(chǎn)生幾個高峰:
1.當設備通過無線網(wǎng)發(fā)送數(shù)據(jù)的時候,為了使用硬件,這里會出現(xiàn)一個喚醒好點高峰。
2.接下來還有一個高數(shù)值,這是發(fā)送數(shù)據(jù)包消耗的電量,
3.然后接受數(shù)據(jù)包也會消耗大量電量 也看到一個峰值。
開啟無線模式這個過程非常耗電,那么硬件這塊為了防止頻繁開啟關閉耗電,采取了一個無奈的辦法,會在一個小段時間內(nèi)保持開啟模式,防止短時間內(nèi)還有數(shù)據(jù)包需要接收,也就是圖中的Keep Awake的那一段。
(1)電量數(shù)據(jù)收集
Android 5.0及以上的設備, 允許我們通過adb命令dump出電量使用統(tǒng)計信息.
1.因為電量統(tǒng)計數(shù)據(jù)是持續(xù)的, 統(tǒng)計我們的待測試App之前先reset下, 連上設備, 命令行執(zhí)行:
2.斷開測試設備, 操作我們的待測試App.
3.重新連接設備, 使用adb命令導出相關統(tǒng)計數(shù)據(jù):
導出的統(tǒng)計數(shù)據(jù)存儲到bugreport.txt, 此時我們可以借助如下工具來圖形化展示電池的消耗情況.
注意, 官方SDK文檔導出文件方式為:
adb shell dumpsys batterystats > batterystats.txt
使用Python historian.py batterystats.txt > batterystats.html查看數(shù)據(jù)
是battery-historian老版本的使用方式. 目前Battery Historian已更新2.0版本, 推薦使用bugreport方式導出數(shù)據(jù)分析, 可以看到更多信息.
(2)電量分析工具Battery Historian
工具開源地址: https://github.com//battery-historian
根據(jù)gitbub上面介紹,Battery History工具的安裝有兩種方式:
1.通過安裝Docker環(huán)境來安裝。(需要)
docker只支持Windows10
Gitbub上面是這樣的命令及地址:
2.通過編譯gitbub上面的源碼來安裝。
(1)Go環(huán)境安裝:
1.下載
下載目錄:https://golang.org/doc/install
https://golang.org/doc/install?download=go1.7.3.windows-amd64.msi
2.安裝go
3.配置GOROOT和GOPATH
a. GOROOT的作用是告訴Go 命令和其他相關工具,在哪里去找到安裝在你系統(tǒng)上的Go包,所以這里配置的是GO的安裝目錄
b.GOPATH可以簡單理解為是工程的目錄,所以創(chuàng)建一個GO的工程路徑
C.后配置一下環(huán)境變量,把Go的bin目錄放到path環(huán)境變量中
D. 檢查Go是否安裝成功,打開命令行輸入Go version
(2)安裝Git
1.點擊下載【下載】; (https://git-scm.com/ )
2.按照步驟安裝;
3.安裝完成檢查:命令行輸入git version
(3)安裝python
1.點擊下載【下載】,注意僅支持python2.7 (https://www.python.org/ )
2.安裝完成;
3.環(huán)境變量配置,添加Path的路徑,是Python的安裝路徑
4.輸入命令行 python –V(注意是大寫V)檢查是否安裝成功
(4)安裝Java環(huán)境
1.點擊下載【下載】;
2.完成安裝。
(5)下載Battery Historian源碼并且運行
**下載到GOPATH配置目錄下
1.進入到$GOPATH/src/github.com//battery-historian目錄下方
2.運行Battery Historian
1) go run setup.go
等待數(shù)分鐘或者10分鐘左右,如果仍然沒有下載成功,可以手動下載,如下操作
**下載【closure-library】和【closure-compiler】和【flot-axislabels】,解壓放到GOROOT目錄下third_party文件夾下方的的closure-compiler和closure-library和flot-axislabels文件夾 ../battery-historian\third_party;如果沒有均手動創(chuàng)建
2)go run cmd/battery-historian/battery-historian.go
數(shù)據(jù)準備
battery-historian工具需要使用bugreport中的Battery History
1.先斷開adb服務,然后開啟adb服務
adb kill-server 這一步很重要,因為當我們開發(fā)時做電量記錄時會打開很多可能造成沖突的東西。為了保險起見我們重啟adb。
adb devices就會自動連接查找手機。當然也可以adb start-server
2.重置電池數(shù)據(jù)收集
數(shù)據(jù),我們在開始的時候需要通過以下命令來打開電池數(shù)據(jù)的獲取以及重置:
上面的操作相當于初始化操作,如果不這么做會有一大堆的干擾的數(shù)據(jù),看起來會比較痛苦。然后把數(shù)據(jù)線直接拔掉(防止數(shù)據(jù)線造成充放電數(shù)據(jù)干擾),現(xiàn)在做一些測試,手動或者跑一些自動化的case都行。經(jīng)過一段時間后,我們重新連接手機確認adb連上了,運行下面這條命令來將bugreport的信息保存到txt文檔中,
或者用下面的命令也可以:
加上包名可以限制輸出的數(shù)據(jù)是我們要檢測的。
但是這個txt的數(shù)據(jù)可讀性不強。接下來我們就要用到這個battery-historian工具了。
分析數(shù)據(jù)
各個參數(shù)的意義
首先我們在bugreport.txt找到Battery History數(shù)據(jù)欄類似下面的信息:
你在html中信息都能從bugreport.txt中找到相應的信息。
現(xiàn)在來分析各個指標代表的意義:
橫坐標
上面的10,20代表的就是秒的意思,它是以一分鐘為周期,到第60秒的時候變?yōu)?。橫坐標就是一個時間范圍,咱們的例子中統(tǒng)計的數(shù)據(jù)是以重置為起點,獲取bugreport內(nèi)容時刻為終點。我們一共采集了多長時間的數(shù)據(jù),圖表下也有信息說明。(經(jīng)其他人的反饋,這個坐標間隔是會隨著時間的長度發(fā)生改變,所以要以你的實際情況為準。這個縮放級別可以調(diào)整的,如下圖:)
縱坐標
| 數(shù)據(jù)項 | 含義 |
|---|---|
| battery_level | 電量,可以看出電量的變化 |
| plugged | 充電狀態(tài),這一欄顯示是否進行了充電,以及充電的時間范圍 |
| screen | 屏幕是否點亮,這一點可以考慮到睡眠狀態(tài)和點亮狀態(tài)下電量的使用信息 |
| top | 該欄顯示當前時刻哪個app處于上層,就是當前手機運行的app,用來判斷某個app對手機電量的影響,這樣也能判斷出該app的耗電量信息。該欄記錄了應用在某一個時刻啟動,以及運行的時間,這對我們比對不同應用對性能的影響有很大的幫助 |
| wake_lock | wake_lock 該屬性是記錄wake_lock模塊的工作時間。是否有停止的時候等 |
| running | 界面的狀態(tài),主要判斷是否處于idle的狀態(tài)。用來判斷無操作狀態(tài)下電量的消耗 |
| Job | 后臺的工作,比如服務service的運行 |
| data_conn | 數(shù)據(jù)連接方式的改變,上面的edge是說明采用的gprs的方式連接網(wǎng)絡的。此數(shù)據(jù)可以看出手機是使用2g,3g,4g還是wifi進行數(shù)據(jù)交換的。這一欄可以看出不同的連接方式對電量使用的影響 |
| status | 電池狀態(tài)信息,有充電,放電,未充電,已充滿,未知等不同狀態(tài) |
| phone_signal_strength | 手機信號狀態(tài)的改變。 這一欄記錄手機信號的強弱變化圖,依次來判斷手機信號對電量的影響 |
| health | 電池健康狀態(tài)的信息,這個信息一定程度上反映了這塊電池使用了多長時間 |
| plug | 充電方式,usb或者插座,以及顯示連接的時間 |
| Sync | 是否跟后臺同步 |
| phone_in_call | 是否進行通話 |
| gps | gps是否開啟 |
Track Battery Status & Battery Manager
我們可以通過下面的代碼來獲取手機的當前充電狀態(tài):
在上面的例子演示了如何立即獲取到手機的充電狀態(tài),得到充電狀態(tài)信息之后,我們可以有針對性的對部分代碼做優(yōu)化。比如我們可以判斷只有當前手機為AC充電狀態(tài)時 才去執(zhí)行一些非常耗電的操作。
屏幕喚醒
有些時候我們需要改變Android系統(tǒng)默認的這種狀態(tài):比如玩游戲時我們需要保持屏幕常亮,比如一些下載操作不需要屏幕常亮但需要CPU一直運行直到任務完成。
好的方式是在Activity中使用FLAG_KEEP_SCREEN_ON 的Flag。
另一個方式是在布局文件中使用android:keepScreenOn屬性:
android:keepScreenOn = ” true “的作用和FLAG_KEEP_SCREEN_ON一樣。使用代碼的好處是你允許你在需要的地方關閉屏幕。
注意:一般不需要人為的去掉FLAG_KEEP_SCREEN_ON的flag,windowManager會管理好程序進入后臺回到前臺的的操作。如果確實需要手動清掉常亮的flag,使用getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
Wakelock and Battery Drain
假設你的手機里面裝了大量的社交類應用,即使手機處于待機狀態(tài),也會經(jīng)常被這些應用喚醒用來檢查同步新的數(shù)據(jù)信息。一個簡單的喚醒手機的方法是使用PowerManager.WakeLock的API來保持CPU工作并防止屏幕變暗關閉。這使得手機可以被喚醒,執(zhí)行工作,然后回到睡眠狀態(tài)。知道如何獲取WakeLock是簡單的,可是及時釋放WakeLock也是非常重要的,不恰當?shù)氖褂肳akeLock會導致嚴重錯誤。例如網(wǎng)絡請求的數(shù)據(jù)返回時間不確定,導致本來只需要10s的事情一直等待了1個小時,這樣會使得電量白白浪費了。這也是為何使用帶超時參數(shù)的wakelock.acquice()方法是很關鍵的。
wake_lock鎖主要是相對系統(tǒng)的休眠而言的,意思就是我的程序給CPU加了這個鎖那系統(tǒng)就不會休眠了,這樣做的目的是為了全力配合我們程序的運行。有的情況如果不這么做就會出現(xiàn)一些問題,比如微信等及時通訊的心跳包會在熄屏不久后停止網(wǎng)絡訪問等問題。所以微信里面是有大量使用到了wake_lock鎖。
wake_lock:兩種鎖,一種計數(shù)鎖;非計數(shù)鎖(鎖了很多次,只需要release一次就可以解除了)
喚醒鎖可劃分為并識別四種用戶喚醒鎖:
| 標記值 | CPU | 屏幕 | 鍵盤 |
|---|---|---|---|
| PARTIAL_WAKE_LOCK | 開啟 | 關閉 | 關閉 |
| 標記值 | 開啟 | 變暗 | 關閉 |
| 標記值 | 開啟 | 變亮 | 關閉 |
| 標記值 | 開啟 | 變亮 | 變亮 |
自 API 等級 17 開始,F(xiàn)ULL_WAKE_LOCK 被棄用。 改為使用 FLAG_KEEP_SCREEN_ON。
添加喚醒鎖權限:
直接使用喚醒鎖:
注意:在使用該類的時候,必須保證acquire和release是成對出現(xiàn)的。不然當我們業(yè)務已經(jīng)不需要時,當CPU處于喚醒狀態(tài),這個時候就會損耗多余的電量。
但是僅僅設置超時并不足夠解決問題,例如設置多長的超時比較合適?什么時候進行重試等等?解決上面的問題,正確的方式可能是使用非精準定時器。通常情況下,我們會設定一個時間進行某個操作,但是動態(tài)修改這個時間也許會更好。例如,如果有另外一個程序需要比你設定的時間晚5分鐘喚醒,好能夠等到那個時候,兩個任務捆綁一起同時進行,這就是非精確定時器的核心工作原理。我們可以定制計劃的任務,可是系統(tǒng)如果檢測到一個更好的時間,它可以推遲你的任務,以節(jié)省電量消耗。
JobScheduler
JobSchedule的宗旨就是把一些不是特別緊急的任務放到更合適的時機批量處理。
自定義一個Service類,繼承自JobService
記得在Manifest文件內(nèi)配置Service
創(chuàng)建工作計劃
本站文章版權歸原作者及原出處所有 。內(nèi)容為作者個人觀點, 并不代表本站贊同其觀點和對其真實性負責,本站只提供參考并不構成任何投資及應用建議。本站是一個個人學習交流的平臺,網(wǎng)站上部分文章為轉載,并不用于任何商業(yè)目的,我們已經(jīng)盡可能的對作者和來源進行了通告,但是能力有限或疏忽,造成漏登,請及時聯(lián)系我們,我們將根據(jù)著作權人的要求,立即更正或者刪除有關內(nèi)容。本站擁有對此聲明的最終解釋權。