Android最小化定期更新造成的影響

2018-08-02 17:42 更新

編寫(xiě):kesenhoo - 原文:http://developer.android.com/training/efficient-downloads/regular_updates.html

最佳的定期更新頻率是不確定的,通常由設(shè)備狀態(tài),網(wǎng)絡(luò)連接狀態(tài),用戶行為與用戶顯式定義的偏好而決定。

Optimizing Battery Life這一章有討論如何根據(jù)主設(shè)備狀態(tài)來(lái)修改更新頻率,從而達(dá)到編寫(xiě)一個(gè)低電量消耗的程序。可執(zhí)行的操作包括當(dāng)斷開(kāi)網(wǎng)絡(luò)連接的時(shí)候去關(guān)閉后臺(tái)服務(wù),在電量比較低的時(shí)候減少更新的頻率等。

這一課會(huì)介紹更新頻率是多少才會(huì)使得更新操作對(duì)無(wú)線電狀態(tài)機(jī)的影響最小。(C2DM與指數(shù)退避算法的使用)

使用 Google Cloud Messaging 來(lái)輪詢

每次 app 去向 server 詢問(wèn)檢查是否有更新操作的時(shí)候,都會(huì)激活無(wú)線電,這樣造成了不必要的能量消耗(在3G情況下,會(huì)差不多消耗20秒的能量)。

Google Cloud Messaging for Android (GCM) 是一個(gè)用來(lái)從 server 到特定 app 傳輸數(shù)據(jù)的輕量級(jí)的機(jī)制。使用 GCM,server 會(huì)在某個(gè) app 需要獲取新數(shù)據(jù)的時(shí)候通知 app 有這個(gè)消息。

比起輪詢方式(app 為了即時(shí)拿到最新的數(shù)據(jù)需要定時(shí)去ping server),GCM 這種由事件驅(qū)動(dòng)的模式會(huì)在僅僅有數(shù)據(jù)更新的時(shí)候通知 app 去創(chuàng)建網(wǎng)絡(luò)連接來(lái)獲取數(shù)據(jù)(很顯然這樣減少了 app 的大量操作,當(dāng)然也減少了很多電量消耗)。

GCM 需要通過(guò)使用持續(xù)的 TCP/IP 連接來(lái)實(shí)現(xiàn)操作。當(dāng)我們可以實(shí)現(xiàn)自己的推送服務(wù),最好使用 GCM(這個(gè)地方應(yīng)該不是傳統(tǒng)意義上的固定IP,可以理解為某個(gè)會(huì)話情況下) 。很明顯,使用 GCM 既減少了網(wǎng)絡(luò)連接次數(shù),也優(yōu)化了帶寬,還減少了對(duì)電量的消耗。

PS:大陸的 Google 框架通常被移除掉,這導(dǎo)致 GCM 實(shí)際上根本沒(méi)有辦法在大陸的 App 上使用。

使用不嚴(yán)格的重復(fù)通知和指數(shù)避退算法來(lái)優(yōu)化輪詢

如果需要使用輪詢機(jī)制,在不影響用戶體驗(yàn)的前提下,設(shè)置默認(rèn)的更新頻率當(dāng)然是越低越好(減少耗電量)。

一個(gè)簡(jiǎn)單的方法是給用戶顯式修改更新頻率的選項(xiàng),允許用戶自己來(lái)處理如何平衡數(shù)據(jù)及時(shí)性與電量的消耗。

當(dāng)設(shè)置安排好更新操作后,可以使用不確定重復(fù)提醒的方式來(lái)允許系統(tǒng)把當(dāng)前這個(gè)操作進(jìn)行定向移動(dòng)(比如推遲一會(huì))。

int alarmType = AlarmManager.ELAPSED_REALTIME;
long interval = AlarmManager.INTERVAL_HOUR;
long start = System.currentTimeMillis() + interval;

alarmManager.setInexactRepeating(alarmType, start, interval, pi);

如果幾個(gè)提醒都安排在某個(gè)點(diǎn)同時(shí)被觸發(fā),那么就可以使得多個(gè)操作在同一個(gè)無(wú)線電狀態(tài)下操作完。

如果可以,請(qǐng)?jiān)O(shè)置提醒的類型為 ELAPSED_REALTIME 或者 RTC 而不是 _WAKEUP。通過(guò)一直等待知道手機(jī)在提醒通知觸發(fā)之前不再處于 standby 模式,進(jìn)一步地減少電量的消耗。

我們還可以通過(guò)根據(jù)最近 app 被使用的頻率來(lái)有選擇性地減少更新的頻率,從而降低這些定期通知的影響。

另一個(gè)方法是在 app 在上一次更新操作之后還未被使用的情況下,使用指數(shù)退避算法 exponential back-off algorithm 來(lái)減少更新頻率。斷言一個(gè)最小的更新頻率和任何時(shí)候使用 app 都去重置頻率通常都是有用的方法。例如:

SharedPreferences sp =
  context.getSharedPreferences(PREFS, Context.MODE_WORLD_READABLE);

boolean appUsed = sp.getBoolean(PREFS_APPUSED, false);
long updateInterval = sp.getLong(PREFS_INTERVAL, DEFAULT_REFRESH_INTERVAL);

if (!appUsed)
  if ((updateInterval *= 2) > MAX_REFRESH_INTERVAL)
    updateInterval = MAX_REFRESH_INTERVAL;

Editor spEdit = sp.edit();
spEdit.putBoolean(PREFS_APPUSED, false);
spEdit.putLong(PREFS_INTERVAL, updateInterval);
spEdit.apply();

rescheduleUpdates(updateInterval);
executeUpdateOrPrefetch();

初始化一個(gè)網(wǎng)絡(luò)連接的花費(fèi)不會(huì)因?yàn)槭欠癯晒ο螺d了數(shù)據(jù)而改變。對(duì)于那些成功完成是很重要的時(shí)間敏感的傳輸,我們可以使用指數(shù)退避算法來(lái)減少重復(fù)嘗試的次數(shù),這樣能夠避免浪費(fèi)電量。例如:

private void retryIn(long interval) {
  boolean success = attemptTransfer();

  if (!success) {
    retryIn(interval*2 < MAX_RETRY_INTERVAL ?
            interval*2 : MAX_RETRY_INTERVAL);
  }
}

另外,對(duì)于可以容忍失敗連接的傳輸(例如定期更新),我們可以簡(jiǎn)單地忽略失敗的連接和傳輸嘗試。


筆者結(jié)語(yǔ):這一課講到GCM與指數(shù)退避算法等,其實(shí)這些細(xì)節(jié)很值得我們注意,如果能在實(shí)際項(xiàng)目中加以應(yīng)用,很明顯程序的質(zhì)量上升了一個(gè)檔次!


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)