Android JobScheduler的使用和原理

我們先看一下JobScheduler的使用沈堡,了解一下JobScheduler的用法,在看一下JobScheduler的實現(xiàn)源碼燕雁。

先看一下如何使用诞丽,翻譯自tutsplus

JobScheduler允許開發(fā)者創(chuàng)建在后臺執(zhí)行的job,當(dāng)預(yù)置的條件被滿足時拐格,這些Job將會在后臺被執(zhí)行僧免。

在Android開發(fā)中,我們會遇到很多這樣的情況捏浊,比如在未來的某個時間點或者未來滿足某種條件(比如插入電源或者連接WiFi)的情況下下去執(zhí)行一些操作懂衩。在Android L上,Google提供了一個叫做JobScheduler的組件來幫助我們處理這種情況。

JobScheduler Api可以在我們的App中執(zhí)行一些操作勃痴,這些操作將會在我們預(yù)置的一些條件被滿足的時候被執(zhí)行谒所。和AlarmManager不一樣,執(zhí)行這些操作的時間并不是嚴格準確的沛申。 JobScheduler會把一系列的job收集起來一起執(zhí)行劣领,這樣既允許我們的job被執(zhí)行,又能兼顧到手機電量的使用情況铁材,達到節(jié)電的目的尖淘。

如何使用JobScheduler Api
  1. 創(chuàng)建JobService

首先要確保我們創(chuàng)建的App最小支持的SDK在Android L以上,因為到目前為止著觉,還沒有兼容包來提供這個功能村生。

在我們的工程中寫一個繼承與JobService的Service(比如叫JobSchedulerService),這個Service提供了兩個回調(diào)方法饼丘,一個是onStartJob(JobParameters params)onStopJob(JobParameters params)趁桃。

public class JobSchedulerService extends JobService{
  @Overrid
  public boolean onStartJob(JobParameters params){
    return false;
  }

  @Override
  public boolean onStopJob(JobParameters params){
    return false;
  }
}
  • onStartJob

當(dāng)系統(tǒng)要觸發(fā)執(zhí)行我們的Job的時候,會調(diào)用onStartJob方法肄鸽。這個方法會返回一個布爾型的值卫病。

當(dāng)返回false的時候,系統(tǒng)會認為onStartJob這個方法返回的時候典徘,我們要做的工作已經(jīng)做完了蟀苛,這不是一個耗時的工作。

當(dāng)返回true的時候逮诲,系統(tǒng)會認為我們要執(zhí)行一個耗時的工作帜平,在onStartJob這個方法返回的時候,我們的工作仍然在異步執(zhí)行梅鹦。當(dāng)我們的工作執(zhí)行完成的時候裆甩,我們必須手動調(diào)用jobFinished(JobParameters params, boolean needRescheduled)

務(wù)必要注意,如果onStartJob返回了true,在異步工作執(zhí)行完成之后帘瞭,我們必須手動調(diào)用jobFinished方法淑掌,如果不調(diào)用jobFinished蒿讥,系統(tǒng)會一直認為我們在執(zhí)行當(dāng)前Job蝶念,那么系統(tǒng)就不會再入隊其他的Job去執(zhí)行,也就是說JobScheduler的執(zhí)行隊列就會被阻塞了

  • onStopJob

當(dāng)系統(tǒng)收到一個cancel job的請求時芋绸,并且這個job仍然在執(zhí)行媒殉,系統(tǒng)就會調(diào)用onStopJob方法。

也就是說在系統(tǒng)受到取消請求時摔敛,并不會一定會調(diào)用onStopJob方法廷蓉,只有onStartJob返回true的時候,才會調(diào)用onStopJob,否則不調(diào)用桃犬。
但不論是否調(diào)用onStopJob方法刹悴,系統(tǒng)受到取消請求時,都會取消該job(具體怎么取消攒暇,在講源碼的時候在分析).

需要注意的是土匀,JobService是運行在我們應(yīng)用的主線程,這意味著我們需要開啟新線程或者使用Handler或者AsyncTask來處理耗時的工作形用。
為了簡單起見就轧,下面的代碼使用了一個Handler來處理耗時工作,并且在處理的耗時工作也僅僅是彈出一個Toast.

private Handler mJobHandler = new Handler( new Handler.Callback() {
    @Override
    public boolean handleMessage( Message msg ) {
        Toast.makeText( getApplicationContext(), 
            "JobService task running", Toast.LENGTH_SHORT )
            .show();
        //請注意,我們手動調(diào)用了jobFinished方法田度。
        //當(dāng)onStartJob返回true的時候妒御,我們必須手動調(diào)用jobFinished方法
        //否則該應(yīng)用中的其他job將不會被執(zhí)行
        jobFinished( (JobParameters) msg.obj, false );
        return true;
    }
} );

jobFinished(JobParameters params, boolean needRescheduled)中的兩個參數(shù),第一個參數(shù)JobParameter來自于onStartJob(JobParameters params)中的params镇饺,這也說明了如果我們想要在onStartJob中執(zhí)行異步操作乎莉,必須要保存下來這個JobParameter

接下來我們改造一下原來的onStartJobonStopJob奸笤,

@Override
public boolean onStartJob(JobParameters params) {
    //這里我們啟用一個Handler來模擬耗時操作
    //注意到我們在使用Hanlder的時候把傳進來的JobParameters保存下來了
    mJobHandler.sendMessage( Message.obtain( mJobHandler, 1, params ) );
    //注意這里我們返回了true,因為我們要做耗時操作梦鉴。
    //返回true意味著耗時操作花費的事件比onStartJob執(zhí)行的事件更長
    //并且意味著我們會手動的調(diào)用jobFinished方法
    return true;
}
 
@Override
public boolean onStopJob(JobParameters params) {
    mJobHandler.removeMessages( 1 );
    return false;
}

要使該JobScheduler能夠正常工作,必須在AndroidManifest.xml中注冊揭保,并聲明權(quán)限

<service android:name=".JobSchedulerService"
    android:permission="android.permission.BIND_JOB_SERVICE" />
  1. 創(chuàng)建JobScheduler
    要使用我們創(chuàng)建的JobService肥橙,我們必須系統(tǒng)的JobScheduler服務(wù),如下
mJobScheduler = (JobScheduler) 
    getSystemService( Context.JOB_SCHEDULER_SERVICE );

然后使用JobInfo.Builder來設(shè)置我們JobScheduler的觸發(fā)條件

//Builder構(gòu)造方法接收兩個參數(shù)秸侣,第一個參數(shù)是jobId存筏,每個app或者說uid下不同的Job,它的jobId必須是不同的
//第二個參數(shù)是我們自定義的JobService,系統(tǒng)會回調(diào)我們自定義的JobService中的onStartJob和onStopJob方法
JobInfo.Builder builder = new JobInfo.Builder( 1,
        new ComponentName( getPackageName(), 
            JobSchedulerService.class.getName() ) );
//指定每三秒鐘重復(fù)執(zhí)行一次
builder.setPeriodic( 3000 );

JobInfo.Builder可以設(shè)置很多參數(shù)味榛,但是有一些參數(shù)是互斥的椭坚,同時設(shè)置了之后會拋出異常,下面詳細說明一下:

setMinimumLatency(long minLatencyMillis):這個方法指定我們的Job至少要多少毫秒之后執(zhí)行搏色,比如setMinimumLatency(5000),就表明我們這是了這個JobScheduler之后善茎,這個Job至少要5秒之后執(zhí)行,前五秒肯定是不會執(zhí)行的频轿。這個參數(shù)和setPeriodic互斥垂涯。兩個同時設(shè)置會拋出異常。

setOverrideDeadline(long maxExecutionDelayMillis):這個方法指定我們的Job在某段時間之后必須執(zhí)行航邢,即使設(shè)置的其他條件不滿足(比如我們還設(shè)置了要求充電耕赘,連接wifi等條件)。這是一個嚴格準時的執(zhí)行膳殷,比如setOverrideDeadline(5000)就表明這個Job在第五秒的時候會準時執(zhí)行操骡,而忽略其他的條件。這個方法也和setPerioidc互斥。

setPersisted(boolean isPersisted):來設(shè)置是否重啟之后繼續(xù)schedule該Job

setRequiredNetworkType(int networkType):來啟動我們這個Job時所需要的網(wǎng)絡(luò)類型册招,一共有三個值JobInfo.NETWORK_TYPE_NONE表明啟動我們這個Job時不需要任何的網(wǎng)絡(luò)連接岔激;JobInfo.NETWORK_TYPE_ANY表明啟動我們這個Job時只要連著網(wǎng)就可以,不要求網(wǎng)絡(luò)類型是掰。JobInfo.NETWORK_TYPE_UNMETERED表明啟動我們這個Job時需要連接Wifi.

setRequiresCharging(boolean requiresCharging)來表示啟動我們這個Job時是否需要連接電源

setRequiresDeviceIdle(boolean requiresDeviceIdle):來表示啟動我們這個Job時是否需要機器處于空閑狀態(tài)鹦倚。

務(wù)必要注意,同時使用setRequiredNetworkType(int networkType), setRequiresCharging(boolean requireCharging)setRequiresDeviceIdle(boolean requireIdle)這三個條件冀惭,可能導(dǎo)致我們的Job永遠都不會執(zhí)行震叙。這個時候我們需要setOverrideDeadline(long time)來確保我們的Job肯定能被執(zhí)行一次

當(dāng)以上兩步都執(zhí)行完畢之后,我們就可以schedule我們的Job了

if( mJobScheduler.schedule( builder.build() ) <= 0 ) {
    //If something goes wrong
}

JobSchedulerschedule方法返回一個整型散休。當(dāng)schedule失敗的時候會返回一個負數(shù)媒楼,成功的時候會返回我們在創(chuàng)建JobInfo.Builder時傳入的JobId.

JobScheduler提供了兩個方法來取消Job,一個是cancel(int jobId),該方法取消指定的Job戚丸,一個是cancelAll來取消所有的Job划址。

這就是JobScheduler大致的使用流程,下一篇會分析一下JobScheduler的源碼限府。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末夺颤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子胁勺,更是在濱河造成了極大的恐慌世澜,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件署穗,死亡現(xiàn)場離奇詭異寥裂,居然都是意外死亡,警方通過查閱死者的電腦和手機案疲,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門封恰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人褐啡,你說我怎么就攤上這事诺舔。” “怎么了备畦?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵低飒,是天一觀的道長。 經(jīng)常有香客問我萍恕,道長逸嘀,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任允粤,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘类垫。我一直安慰自己司光,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布悉患。 她就那樣靜靜地躺著残家,像睡著了一般。 火紅的嫁衣襯著肌膚如雪售躁。 梳的紋絲不亂的頭發(fā)上坞淮,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音陪捷,去河邊找鬼回窘。 笑死,一個胖子當(dāng)著我的面吹牛市袖,可吹牛的內(nèi)容都是我干的啡直。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼苍碟,長吁一口氣:“原來是場噩夢啊……” “哼酒觅!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起微峰,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤舷丹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蜓肆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掂榔,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年症杏,在試婚紗的時候發(fā)現(xiàn)自己被綠了装获。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡厉颤,死狀恐怖穴豫,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情逼友,我是刑警寧澤精肃,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站帜乞,受9級特大地震影響司抱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜黎烈,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一习柠、第九天 我趴在偏房一處隱蔽的房頂上張望匀谣。 院中可真熱鬧,春花似錦资溃、人聲如沸武翎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宝恶。三九已至,卻和暖如春趴捅,著一層夾襖步出監(jiān)牢的瞬間垫毙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工拱绑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留综芥,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓欺栗,卻偏偏與公主長得像毫痕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子迟几,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,592評論 2 353

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