性能優(yōu)化-耗電優(yōu)化

耗電優(yōu)化

耗電檢測(cè)工具

Battery Historian是一款Google提供的Android系統(tǒng)電量分析工具,能直觀顯示手機(jī)的電量消耗過(guò)程傍菇。

Battery Historian使用步驟

  1. 初始化Battery Historian谍椅,使用adb命令
adb shell dumpsys batterystats --enable full-wake-history

adb shell dumpsys batterystats --reset
  1. 初始化后误堡,操作需要測(cè)試耗電的場(chǎng)景
  2. 經(jīng)過(guò)2步驟后,用下面命令將bugreport信息保存為bugreport.txt文件
adb bugreport > bugreport.txt

打開(kāi)可看到耗電數(shù)據(jù)雏吭,但可讀性差锁施,下面轉(zhuǎn)成html

  1. 生成html報(bào)告
python historian.py -a bugreport.txt > battery.html

historian.py需要python環(huán)境,historian.py腳本可從github下載

historian.py需要和bugreport.txt在同個(gè)目錄下

  1. 使用Chrome打開(kāi)生成但HTML文件杖们,即可查看詳細(xì)報(bào)告悉抵。

報(bào)告參數(shù)解析

image.png

三大模塊省電優(yōu)化

移動(dòng)設(shè)備的耗電主要集中在三個(gè)模塊:顯示(屏幕)、CPU胀莹、網(wǎng)絡(luò)模塊(蜂窩網(wǎng)絡(luò))

1. 顯示

對(duì)應(yīng)用程序來(lái)說(shuō)基跑,在使用時(shí)屏幕顯示的耗電基本沒(méi)多少優(yōu)化空間,但可以根據(jù)是否長(zhǎng)時(shí)間沒(méi)有操作進(jìn)入熄屏狀態(tài)描焰。

2. 網(wǎng)絡(luò)

通常情況下媳否,Wi-Fi連接網(wǎng)絡(luò)時(shí)的功耗低于使用移動(dòng)網(wǎng)絡(luò)的功耗。
使用移動(dòng)網(wǎng)絡(luò)傳輸數(shù)據(jù)荆秦,電量的消耗有以下3中狀態(tài):

  • Full power:高功率狀態(tài)篱竭,允許最大傳輸速率操作
  • Low power:低功耗狀態(tài),電量消耗大概是Full power的50%
  • Standby:空閑狀態(tài)步绸,沒(méi)有數(shù)據(jù)傳輸時(shí)掺逼,電量消耗最少。

在應(yīng)用中每創(chuàng)建一個(gè)新的網(wǎng)絡(luò)連接瓤介,網(wǎng)絡(luò)模塊都會(huì)轉(zhuǎn)換到高功率狀態(tài)吕喘,在傳完后回到低功耗赘那,轉(zhuǎn)換過(guò)程5秒,最后轉(zhuǎn)空閑態(tài)氯质。每個(gè)數(shù)據(jù)傳輸都會(huì)導(dǎo)致20秒的電量消耗募舟。

Wi-Fi的耗電與包率(每秒發(fā)送和接受的包數(shù))和通道率(網(wǎng)速)這兩個(gè)因素有關(guān)。

優(yōu)化網(wǎng)絡(luò)連接降低電量消耗的方案:

  • 盡量在Wi-Fi下使用數(shù)據(jù)傳輸(一些不緊急的判斷在Wi-Fi環(huán)境在傳輸)
  • 使用Wi-Fi傳輸數(shù)據(jù)時(shí)闻察,應(yīng)盡可能增大每個(gè)包的大泄敖浮(不超過(guò)MTU),并降低并發(fā)包的頻率辕漂。
  • 在蜂窩網(wǎng)絡(luò)下呢灶,最好做到批量執(zhí)行網(wǎng)絡(luò)請(qǐng)求,盡量避免頻繁的間隔網(wǎng)絡(luò)請(qǐng)求钉嘹。
  • 壓縮數(shù)據(jù)格式鸯乃,比如使用GZIP壓縮傳輸減少數(shù)據(jù)量

3. CPU

為了省電和高效管理CPU,Linux內(nèi)核提供5種變頻模式供用戶選擇使用隧期。但調(diào)頻需要在Root環(huán)境下飒责,應(yīng)用開(kāi)發(fā)中一般無(wú)法使用赘娄。在應(yīng)用中需要注意的是如何減少CPU的開(kāi)銷以達(dá)到省電的目的仆潮,比如減少計(jì)算量。

應(yīng)用常用優(yōu)化方案

計(jì)算優(yōu)化

縮短代碼產(chǎn)生指令運(yùn)行的時(shí)間遣臼,進(jìn)而減少某個(gè)應(yīng)用程序?qū)PU時(shí)間片的總占用時(shí)間性置。浮點(diǎn)運(yùn)算比整數(shù)運(yùn)算更消耗CPU時(shí)間片,耗電也會(huì)增加揍堰,所以盡量減少浮點(diǎn)運(yùn)算
避免浮點(diǎn)運(yùn)算的方法:

  • 除法變乘法
  • 充分利用移位
  • 查表法鹏浅,直接使用映射關(guān)系,但這個(gè)會(huì)增加內(nèi)存開(kāi)銷屏歹,視具體場(chǎng)景而定隐砸。

避免WakeLock使用不當(dāng)

在某些場(chǎng)景,比如社交類應(yīng)用蝙眶、播放器停留在看歌詞頁(yè)面季希,需要喚醒手機(jī)不要進(jìn)入息屏睡眠狀態(tài)。最常用的喚醒手機(jī)的方法是使用PowerManager.WakeLock來(lái)保持CPU工作并防止屏幕自動(dòng)變暗關(guān)閉幽纷。

PowerManager負(fù)責(zé)對(duì)Android設(shè)備電源相關(guān)進(jìn)行管理式塌,WakeLock也是一種鎖機(jī)制,只要應(yīng)用中有WakeLock友浸,通過(guò)相應(yīng)參數(shù)去獲取對(duì)應(yīng)的鎖峰尝,即可達(dá)到電源管理目的。

獲取WakeLock

private void acquireWakeLock(Context ctx){
    if(null == mWakeLock){
        PowerManager pm = (PowerManager)ctx.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "TestLockService");
        if(null != mWakeLock){
            mWakeLock.acquire();
        }
    }
}

拿到WakeLock后收恢,可以保持完成需要完成的事武学,但完成后祭往,或者離開(kāi)這個(gè)場(chǎng)景后,需要及時(shí)釋放WakeLock火窒,否則會(huì)帶來(lái)不可預(yù)估的電量消耗链沼。釋放鎖代碼:

private void releaseWakeLock(){
    if(null != mWakeLock){
        mWakeLock.release();
        mWakeLock = null;
    }
}

使用JobScheduler

在Android5.0提供來(lái)一個(gè)JobScheduler組件,只有在一系列的預(yù)置條件滿足時(shí)沛鸵,才執(zhí)行對(duì)應(yīng)的操作括勺,這樣既能省電,有保證來(lái)功能的完整性曲掰〖埠矗可以在以下場(chǎng)景中考慮使用JobScheduler:

  • 重要不緊急的任務(wù),如定期數(shù)據(jù)庫(kù)數(shù)據(jù)更新和數(shù)據(jù)上報(bào)
  • 耗電較大的任務(wù)栏妖,比如充電是才執(zhí)行數(shù)據(jù)庫(kù)備份
  • 不緊急可以不執(zhí)行的網(wǎng)絡(luò)任務(wù)乱豆,如可在Wi-Fi下才執(zhí)行預(yù)加載數(shù)據(jù)
  • 可以批量執(zhí)行的任務(wù)

使用JobScheduler的兩個(gè)步驟:

  1. 創(chuàng)建JobScheduler

創(chuàng)建JobScheduler,用來(lái)初始化一個(gè)JobScheduler以及設(shè)置觸發(fā)JobScheduler執(zhí)行任務(wù)的條件吊趾。

  • 通過(guò)getSystemService()獲取一個(gè)JobScheduler對(duì)象
private JobScheduler mJS = null;
public JobSchedulerManager(Context ctx){
    mContext = ctx;
    mJS = (JobScheduler)mContext.getSystemService(Context.JOB_SCHEDULER_SERVICE);
}
  • 創(chuàng)建一個(gè)JobInfo宛裕,描述一個(gè)任務(wù)的執(zhí)行ID,以及觸發(fā)這個(gè)任務(wù)的條件
public boolean addJobSchedulerTask(int task_id){
    JobInfo.Builder builder = new JobInfo.Builder(task_id, new ComponentName("PackgeName", JobSchedulerService.class.getName()));
    
    switch(task_id){
        case 1:
            builder.setPeriodic(1000);
            break;
        case 2:
            builder.setPersisted(false);
            break;
        default:
    }
    if(mJS != null){
        return mJS.schedule(builder.build()) > JobScheduler.RESULT_FAILURE;
    }else{
        return false;
    }
}
image.png
  1. 創(chuàng)建JobSchedulerService繼承JobService
public class JobSchedulerService extends JobService{
    @Override
    public boolean onStartJob(JobParameters params){
        //執(zhí)行具體的任務(wù)论泛,最好在異步線程
        return false;
    }
     @Override
    public boolean onStopJob(JobParameters params){
        //取消一個(gè)任務(wù)
        return false;
    }
}

在AndroidManifest.xml中注冊(cè)服務(wù)

<service android:name="JobSchedulerService"
         android:permission="android.permission.BIND_JOB_SERVICE">
</service>

JobSchedulerService必須實(shí)現(xiàn)兩個(gè)方法onStartJob(JobParameters params)和onStopJob(JobParameters params)

  • 任務(wù)開(kāi)始時(shí)揩尸,執(zhí)行onStartJob(JobParameters params)方法,觸發(fā)已經(jīng)被執(zhí)行的任務(wù)屁奏。執(zhí)行完畢岩榆,需要調(diào)用jobFinished(JobParameters params, boolean needsReschedule)來(lái)通知系統(tǒng)。
  • 系統(tǒng)接受到取消請(qǐng)求坟瓢,調(diào)用onStopJob(JobParameters params)方法取消正在等待執(zhí)行的任務(wù)勇边。

注意:JobService運(yùn)行在主線程,如果耗時(shí)任務(wù)折联,要異步操作來(lái)執(zhí)行粒褒。

本文參考書(shū)籍《Android應(yīng)用性能優(yōu)化最佳實(shí)踐》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市诚镰,隨后出現(xiàn)的幾起案子奕坟,更是在濱河造成了極大的恐慌,老刑警劉巖怕享,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件执赡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡函筋,警方通過(guò)查閱死者的電腦和手機(jī)沙合,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)跌帐,“玉大人首懈,你說(shuō)我怎么就攤上這事绊率。” “怎么了究履?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵滤否,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我最仑,道長(zhǎng)藐俺,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任泥彤,我火速辦了婚禮欲芹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘吟吝。我一直安慰自己菱父,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布剑逃。 她就那樣靜靜地躺著浙宜,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蛹磺。 梳的紋絲不亂的頭發(fā)上粟瞬,一...
    開(kāi)封第一講書(shū)人閱讀 51,190評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音称开,去河邊找鬼亩钟。 笑死乓梨,一個(gè)胖子當(dāng)著我的面吹牛鳖轰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扶镀,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼蕴侣,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了臭觉?” 一聲冷哼從身側(cè)響起昆雀,我...
    開(kāi)封第一講書(shū)人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蝠筑,沒(méi)想到半個(gè)月后狞膘,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡什乙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年挽封,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片臣镣。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辅愿,死狀恐怖智亮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情点待,我是刑警寧澤阔蛉,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站癞埠,受9級(jí)特大地震影響状原,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜苗踪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一遭笋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧徒探,春花似錦瓦呼、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至碗啄,卻和暖如春质和,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背稚字。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工饲宿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胆描。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓瘫想,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親昌讲。 傳聞我的和親對(duì)象是個(gè)殘疾皇子国夜,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容