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提出來的录平,目前版本還是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后出來的晃择,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ì)越來越長(zhǎng)斥赋,如上圖缰猴。
老實(shí)說,按照國(guó)人的習(xí)慣疤剑,白天手機(jī)想進(jìn)入doze滑绒,基本上上不可能的。沒有誰會(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+才出來的,要兼容5.0之前的焰手,額外再用alramager;而且國(guó)外的還可以使用googleservice(Firebase JobDispatcher)實(shí)現(xiàn)糟描。這就需要開發(fā)者自己來兼容;
后面發(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到來&&沒有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取出來夜赵。

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

workmanager的使用

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

developer上workmanager的官方文檔
使用起來還是很方便的视粮,workmanager.enque(workRequest)就可以了细办,看起來類似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閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卷雕,死亡現(xiàn)場(chǎng)離奇詭異节猿,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)漫雕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門滨嘱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人浸间,你說我怎么就攤上這事太雨。” “怎么了魁蒜?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵囊扳,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我兜看,道長(zhǎng)锥咸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任细移,我火速辦了婚禮搏予,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘弧轧。我一直安慰自己雪侥,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布精绎。 她就那樣靜靜地躺著速缨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捺典。 梳的紋絲不亂的頭發(fā)上鸟廓,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音襟己,去河邊找鬼引谜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛擎浴,可吹牛的內(nèi)容都是我干的员咽。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼贮预,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼贝室!你這毒婦竟也來了契讲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤滑频,失蹤者是張志新(化名)和其女友劉穎捡偏,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體峡迷,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡银伟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了绘搞。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片彤避。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖夯辖,靈堂內(nèi)的尸體忽然破棺而出琉预,到底是詐尸還是另有隱情,我是刑警寧澤蒿褂,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布圆米,位于F島的核電站,受9級(jí)特大地震影響贮缅,放射性物質(zhì)發(fā)生泄漏榨咐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一谴供、第九天 我趴在偏房一處隱蔽的房頂上張望块茁。 院中可真熱鬧,春花似錦桂肌、人聲如沸数焊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)佩耳。三九已至,卻和暖如春谭跨,著一層夾襖步出監(jiān)牢的瞬間干厚,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工螃宙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蛮瞄,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓谆扎,卻偏偏與公主長(zhǎng)得像挂捅,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子堂湖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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

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