我們先看一下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
- 創(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
。
接下來我們改造一下原來的onStartJob
和onStopJob
奸笤,
@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" />
- 創(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
}
JobScheduler
的schedule
方法返回一個整型散休。當(dāng)schedule失敗的時候會返回一個負數(shù)媒楼,成功的時候會返回我們在創(chuàng)建JobInfo.Builder
時傳入的JobId.
JobScheduler提供了兩個方法來取消Job,一個是cancel(int jobId)
,該方法取消指定的Job戚丸,一個是cancelAll
來取消所有的Job划址。
這就是JobScheduler大致的使用流程,下一篇會分析一下JobScheduler的源碼限府。