android workmanager

目錄

  • google后臺(tái)任務(wù)推薦方案
  • doze簡(jiǎn)介
  • 從jobservice 到android-job 到workmanager
  • 遇到的一些坑
  • 總結(jié)

先看一下google推薦的后臺(tái)任務(wù)的解決方案

image.png

如圖后臺(tái)任務(wù)可以從三個(gè)維度去考慮:

  • 是否需要立即執(zhí)行
  • 是否需要執(zhí)行完畢
  • 是否需要監(jiān)聽系統(tǒng)的狀態(tài) 如網(wǎng)絡(luò)狀態(tài)等

然后給出了對(duì)應(yīng)的具體的推薦方案

線程池、廣播、前臺(tái)任務(wù)這里暫時(shí)不提,主要看一下新出的workmanager,從圖中可以看出workmanager的使用條件任務(wù)可以適當(dāng)延遲的,即task沒有鬧鐘那種強(qiáng)時(shí)效性。

workmanager是今年google io提出來(lái)的,目前版本還是1.0.0-alpha01,看見alpha就有點(diǎn)慌,后面果然出現(xiàn)bug了,這個(gè)后面再細(xì)說。

背景

為什么要使用workmanager,是alrammanager不好用嗎?
其實(shí)這兩者的作用并不完全一樣;alarmmanager適用于類似鬧鐘那樣必須準(zhǔn)時(shí)喚醒的任務(wù),不管是否處于doze(低耗電和應(yīng)用待機(jī)模式);不過在6.0后的doze里面,alarmmanager需要調(diào)用setAndAllowWhileIdle()
setExactAndAllowWhileIdle()
如果必須要準(zhǔn)時(shí)執(zhí)行的任務(wù)比如股票每日開市提醒只能強(qiáng)行喚醒系統(tǒng),但是也有的是不是要求時(shí)間這么準(zhǔn)確的,比如每隔2天彈一個(gè)notification提示打開app啥的,這種實(shí)效性不那么高的就可以換成jobservice。

簡(jiǎn)單介紹一下doze

相關(guān)文檔

image.png

這個(gè)是android6.0后出來(lái)的,6.0+的設(shè)備上都有這個(gè),目的是為了省電。簡(jiǎn)單的說就是手機(jī)系統(tǒng)發(fā)現(xiàn)一段時(shí)間用戶都沒有在用手機(jī)了,就會(huì)進(jìn)入省電模式,期間不會(huì)處理alarm、網(wǎng)絡(luò)狀態(tài)等,等省電了一段時(shí)間后再給一小段時(shí)間讓所有應(yīng)用統(tǒng)一處理alram等task,然后又進(jìn)入省電狀態(tài)。如果中途一直沒有亮屏、充電等表示用戶開始用手機(jī)了的操作,doze的省電周期會(huì)越來(lái)越長(zhǎng),如上圖。
老實(shí)說,按照國(guó)人的習(xí)慣,白天手機(jī)想進(jìn)入doze,基本上上不可能的。沒有誰(shuí)會(huì)好幾個(gè)小時(shí)不碰手機(jī)吧。所以基本上都是晚上進(jìn)入doze,這也說明了為啥早上亮屏的瞬間手機(jī)好多app會(huì)在同一時(shí)間彈出notification(亮屏就退出了doze,被延遲的alram馬上開始工作)。

那么使用jobservice的優(yōu)勢(shì)在哪兒,我為什么不全部用alarmManager?

使用jobservice的優(yōu)勢(shì)就是doze下,不會(huì)喚醒系統(tǒng),耗電量會(huì)減小。耗電量減小到一定程度,才能達(dá)到googleplay的推薦要求;在國(guó)內(nèi),兩種類型差不多的app,用戶通過電量消耗統(tǒng)計(jì)軟件發(fā)現(xiàn)耗電量低的那個(gè)app,應(yīng)該會(huì)對(duì)它更有好感吧(卸載也是先卸載競(jìng)爭(zhēng)對(duì)手的app 哈哈)。

從jobservice 到android-job 到workmanager

前面說的時(shí)效性不是很強(qiáng)的任務(wù)可以用jobservice(JobScheduler),但是這個(gè)是android5.0+才出來(lái)的,要兼容5.0之前的,額外再用alramager;而且國(guó)外的還可以使用googleservice(Firebase JobDispatcher)實(shí)現(xiàn)。這就需要開發(fā)者自己來(lái)兼容;
后面發(fā)現(xiàn)印象筆記的android-job已經(jīng)實(shí)現(xiàn)了類似的功能;
github上印象筆記的文檔

androidjob的相關(guān)api

任務(wù)調(diào)度類型

  • 普通任務(wù)
    setExecutionWindow(start,end)
  • 特定時(shí)間執(zhí)行的任務(wù)
    setExact(time)
  • 周期任務(wù)
    setPeriodic(long intervalMs, long flexMs)

任務(wù)的執(zhí)行時(shí)間范圍public Builder setExecutionWindow(long startInMs, long endInMs)

  • mStartMs
    Earliest point from which your task is eligible to run.

  • endInMs
    Latest point at which your task must be run. eligible to run.
    這兩個(gè)是時(shí)間窗口的起始時(shí)間,意思是System.currentTimeMillis() + startInMs到System.currentTimeMillis() + endInMs之間執(zhí)行,endInMs對(duì)應(yīng)后面的deadline。
    在setPeriodic(long)和setExact(long)時(shí)不起作用

和周期任務(wù)相關(guān)的參數(shù)Builder setPeriodic(long intervalMs, long flexMs)

  • long mIntervalMs
    這個(gè)是周期執(zhí)行有關(guān)的參數(shù),每隔多久執(zhí)行一次,最低是15分鐘。

  • long mFlexMs
    這個(gè)是周期執(zhí)行有關(guān)的參數(shù),離周期末尾多久這個(gè)job應(yīng)該被執(zhí)行,最低5分鐘。

    JobManager.instance().getConfig().setAllowSmallerIntervalsForMarshmallow(true); // Don't use this in production

    debug模式下設(shè)置這個(gè),可以在api<24的機(jī)子上周期減小到60s,倒數(shù)減小到30s;正式環(huán)境,最低周期15分鐘,倒數(shù)5分鐘。

和任務(wù)執(zhí)行失敗,重新調(diào)度有關(guān)的參數(shù)public Builder setBackoffCriteria(long backoffMs, @NonNull BackoffPolicy backoffPolicy)

  • backoffMs
    非周期性的任務(wù),執(zhí)行失敗后被重新調(diào)度需要等待的時(shí)間,配合著下面的策略使用。
    默認(rèn)開始30s,逐漸增加最多5小時(shí)
  • backoffPolicy
    枚舉,只有線性和指數(shù)增長(zhǎng)兩種方式。

一些二級(jí)條件吧,如果沒有強(qiáng)制要求,會(huì)在deadline時(shí)忽略這些條件執(zhí)行job

  • boolean mRequiresCharging
    是否需要插入設(shè)備(是指充電吧)
    默認(rèn)false,但是如果之前的endInMS到了&&mRequirementsEnforced=false,就會(huì)忽略這個(gè)條件執(zhí)行job

  • boolean mRequiresDeviceIdle
    是否需要等到設(shè)備空閑。同上面一樣,當(dāng)deadline到來(lái)&&沒有mRequirementsEnforced=false時(shí),就會(huì)忽略這個(gè)條件執(zhí)行Job

  • boolean mRequiresBatteryNotLow
    是否禁止低電量。同上,deadline&&有mRequirementsEnforced=false會(huì)忽略。

  • boolean mRequiresStorageNotLow
    是否禁止低存儲(chǔ)空間。這個(gè)只有在android o才有效果

  • NetworkType mNetworkType
    需要等待的網(wǎng)絡(luò)狀態(tài),是netWorkType的枚舉,有好幾種,類似wify 、流量等,默認(rèn)是不需要關(guān)心網(wǎng)絡(luò)狀態(tài)。
    同上條件。

  • boolean mRequirementsEnforced
    這個(gè)就是前面提到的那個(gè)參數(shù),如果設(shè)為false,當(dāng)job到deadline還沒執(zhí)行的時(shí)候,就可以搶救一下。

傳參相關(guān)

  • PersistableBundleCompat mExtras
    帶的額外參數(shù),必須是這種類型,類似bundle。可以在onRunJob方法那里通過傳過去的param取出來(lái)。

可以說android-job很良心了,暴露的api簡(jiǎn)單易用,功能強(qiáng)大。

workmanager的使用

本來(lái)已經(jīng)使用android-job了,但是后面在github文檔的后面看到了官方的說明:由于google出了workmanager,Android-job后面可能不再更新。然后又換到workmanager。

developer上workmanager的官方文檔
使用起來(lái)還是很方便的,workmanager.enque(workRequest)就可以了,看起來(lái)類似google之前出的volley的風(fēng)格,不知道是不是同一批程序員開發(fā)的哈哈。

public class DemoWorker extends Worker {
  public static final String TAG = "work_demo_tag";
  @NonNull @Override public WorkerResult doWork() {
    Data data = getInputData();
    int requestCode = data.getInt(AlarmMgr.ALARM_REQUEST_CODE, -1);
    String strData = data.getString(AlarmMgr.ALARM_NOTIFICATION_DATA, "");
    boolean bNotiClick = data.getBoolean(AlarmMgr.ALARM_NOTIFICATION_CLICK, false);
    Context context = getApplicationContext();
  //your job to do

  //可以再這里調(diào)用下一個(gè)一次性任務(wù),形成周期循環(huán)。
 //現(xiàn)在默認(rèn)執(zhí)行成功,有需要再添加retry back-off相關(guān)邏輯
    return WorkerResult.SUCCESS;
  }
/**
   * @param requestCode requestCode
   * @param strData strData
   * @param bNotiClick bNotiClick
   */
  public static void schedule(final int requestCode, String strData, boolean bNotiClick) {
    WorkManager manager = WorkManager.getInstance();
   //下一次任務(wù)開始時(shí),取消上一次相關(guān)tag類型的任務(wù)(避免網(wǎng)絡(luò)狀態(tài)不太好反復(fù)觸發(fā)網(wǎng)絡(luò)切換廣播的情況)
   //這里如果queue里面存在100個(gè)以上job會(huì)crash,所以需要處理一下
    manager.cancelAllWorkByTag(String.valueOf(requestCode));
    OneTimeWorkRequest oneTimeWorkRequest =
        new OneTimeWorkRequest.Builder(AlarmReceiverWorker.class)
            .addTag(String.valueOf(requestCode))
            .setInputData(new Data.Builder()
                .putInt(AlarmMgr.ALARM_REQUEST_CODE, requestCode)
                .putString(AlarmMgr.ALARM_NOTIFICATION_DATA, strData)
                .putBoolean(AlarmMgr.ALARM_NOTIFICATION_CLICK, bNotiClick)
                .build())
            .build();
    manager.enqueue(oneTimeWorkRequest);
  }
}

需要注意的是隊(duì)列里面任務(wù)(還在等待調(diào)度 未執(zhí)行的那種)不能超過100個(gè),不然會(huì)crash,這是workmanager代碼的限制
workRequest子類有oneTime和periodic,對(duì)應(yīng)一次性任務(wù)和周期性任務(wù);因?yàn)榛旧贤瑯邮菍?duì)jobservice操作,所以方法很類似android-job,可以對(duì)照上面anroid-job用法或者查看developer文檔workmanger簡(jiǎn)介
列一下常見用法

  • 多任務(wù)調(diào)度順序
WorkManager.getInstance()
    // First, run all the A tasks (in parallel):
    .beginWith(workA1, workA2, workA3)
    // ...when all A tasks are finished, run the single B task:
    .then(workB)
    // ...then run the C tasks (in any order):
    .then(workC1, workC2)
    .enqueue();
  • 設(shè)置任務(wù)執(zhí)行的約束條件
// Create a Constraints that defines when the task should run
Constraints myConstraints = new Constraints.Builder()
    .setRequiresDeviceIdle(true)
    .setRequiresCharging(true)
    // Many other constraints are available, see the
    // Constraints.Builder reference
     .build();

// ...then create a OneTimeWorkRequest that uses those constraints
OneTimeWorkRequest compressionWork =
                new OneTimeWorkRequest.Builder(CompressWorker.class)
     .setConstraints(myConstraints)
     .build();
  • 取消任務(wù)除了前面提到的cancleByTag,也可以用uniquework
 OneTimeWorkRequest oneTimeWorkRequest =
          new OneTimeWorkRequest.Builder(AlarmReceiverWorker.class).build();
      WorkManager.getInstance()
          .beginUniqueWork("downloadQueue", ExistingWorkPolicy.REPLACE, oneTimeWorkRequest);

說說坑吧

workermanager的周期任務(wù),有時(shí)不能取消掉之前放到隊(duì)列的任務(wù)。通過cancleByTag也不行,這個(gè)在stackoverflow和github上面的issue也看到有人提過,而且確實(shí)回復(fù)是個(gè)bug,應(yīng)該是alpha版還是有些問題的。
既然周期任務(wù)有坑,我們也可以采用一次性任務(wù)開啟下一個(gè)一次性任務(wù),像鏈表那樣。而且可以避開周期任務(wù)里面源碼對(duì)周期設(shè)置最小15分鐘的限制,不過一般也沒那么流氓要隔幾分鐘就喚醒吧。
但是使用一次性任務(wù)循環(huán)觸發(fā),發(fā)現(xiàn)在小米上測(cè)試,打開app退到后臺(tái)時(shí),alarmmanager android-job workmanager正常,殺掉app,workmanager就不行了;使小米達(dá)到doze的條件,再亮屏,anroid-job也不行了。在小米上暫時(shí)只有alramanager適用(如果有哪位朋友發(fā)現(xiàn)小米上用workmanager有方法可以避開這個(gè)坑,請(qǐng)分享一下)。

還有就是前面提到的,要避開queue里面出現(xiàn)100個(gè)待調(diào)度的job的case。

總結(jié)

最后的做法定時(shí)任務(wù)使用alrammanager,等收到alram廣播后交給worker處理;網(wǎng)絡(luò)狀態(tài)監(jiān)聽任務(wù)直接再接收到廣播后交給worker處理。保證定時(shí),但是收到廣播放到隊(duì)列里面不像之前那樣接收到廣播就串行馬上執(zhí)行了,等系統(tǒng)決定統(tǒng)一處理。

等后面workmanager版本號(hào)把a(bǔ)lpha去掉就更好了;可以先用android-job,等workamanager出穩(wěn)定版本再替換成worker,因?yàn)閍pi太像了,替換的成本也不大。

這篇文章有些細(xì)節(jié)需要后面再進(jìn)行補(bǔ)充。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,055評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,346評(píng)論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,889評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評(píng)論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,118評(píng)論 0 286
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,637評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,558評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,739評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,980評(píng)論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,347評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,702評(píng)論 2 370

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

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,590評(píng)論 25 707
  • 1. WorkManager 1). 簡(jiǎn)介 其實(shí)就是"管理一些要在后臺(tái)工作的任務(wù), -- 即使你的應(yīng)用沒啟動(dòng)也能...
    _凌浩雨閱讀 657評(píng)論 0 1
  • 一寸柔腸一縷絲,千梭萬(wàn)紉九張機(jī)。織就鴛鴦?dòng)蓪?duì),明珠勿復(fù)雙垂淚。 一張機(jī),夏荷殘影雨靡靡,流光漸去添新句。清燈小字...
    離之_905d閱讀 454評(píng)論 0 4
  • yum安裝 1.node.js是用c++寫的,所以電腦環(huán)境首先要有c++的環(huán)境; 2.進(jìn)入你想要安裝的目錄,下載n...
    chenxuxu閱讀 572評(píng)論 0 2
  • 既然緣盡于此,不如就此別過
    熊胖之語(yǔ)閱讀 137評(píng)論 0 0