最近Jobscheduler的使用不當(dāng)導(dǎo)致不少問題,比如定時(shí)任務(wù)不生效或者沖突。歸根結(jié)底是對(duì)Jobscheduler的使用不熟悉以及,其工作原理沒有一個(gè)系統(tǒng)性的了解。本人也曾踩坑,所以下定決心好好熟悉Jobscheduler。
概述
在android開發(fā)中經(jīng)常會(huì)有這樣的需求,開發(fā)者需要在稍后的某個(gè)時(shí)間點(diǎn)或者滿足某個(gè)特定的條件時(shí)去執(zhí)行某個(gè)任務(wù),例如當(dāng)設(shè)備開始充電,或者網(wǎng)絡(luò)狀態(tài)連接到wifi狀態(tài)時(shí)執(zhí)行某些推送通知的任務(wù),jobscheduler就是用來處理這類場景的任務(wù)。
Jobscheduler的android在5.0上針對(duì)于降低功耗而提出來的一種策略方案,自 Android 5.0 發(fā)布以來,JobScheduler 已成為執(zhí)行后臺(tái)工作的首選方式,其工作方式有利于用戶。應(yīng)用可以在安排作業(yè)的同時(shí)允許系統(tǒng)基于設(shè)備狀態(tài)、電源和連接情況等具體條件進(jìn)行優(yōu)化。JobScheduler 可實(shí)現(xiàn)控制和簡潔性,谷歌推出該機(jī)制是想要所有應(yīng)用在執(zhí)行后臺(tái)任務(wù)時(shí)使用它。 在之前的版本上,沒有Job 這個(gè)服務(wù),客戶端代碼如果需要實(shí)現(xiàn)類似的需求,必須要在客戶端代碼用alarm ,network, battery等服務(wù)來多次判斷條件,以實(shí)現(xiàn)此類需求,對(duì)于App 開發(fā)者來說,其實(shí)是一個(gè)比較麻煩和復(fù)雜的代碼邏輯。而job 的出現(xiàn),很大程度上把此類條件判斷邏輯放到服務(wù)端去判斷,當(dāng)所有限制條件滿足時(shí)候,客戶端觸發(fā)job
如何使用jobscheduler
應(yīng)用如果想使用JobScheduler API的話,首先需要?jiǎng)?chuàng)建自己需要執(zhí)行的任務(wù)信息,創(chuàng)建任務(wù)的方法在谷歌官方文檔上已經(jīng)有詳細(xì)介紹,這里只是放出一個(gè)實(shí)例:
JobInfo updateJob = new JobInfo.Builder(UPDATEDB_JOB_ID, new ComponentName(context, TimedUpdateCleanUpDbJobService.class))
.setPeriodic(UPDATE_MIN_TIME)// 設(shè)置循環(huán)時(shí)間
.setPersisted(true)// 是否是持久化的job,如果是,開機(jī)后便會(huì)設(shè)置到系統(tǒng)中,需要RECEIVE_BOOT_COMPLETED權(quán)限
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) // 需要非計(jì)費(fèi)網(wǎng)絡(luò)
.setRequiresDeviceIdle(true)//需要設(shè)備空閑
.build();
JobScheduler scheduler = getSystemService(Context.JOB_SERVICE);
scheduler.scheduler(updateJob);
上面的一個(gè)任務(wù)是在開機(jī)之后執(zhí)行初始化的操作。其實(shí)并不需要延時(shí)1s,但是這里需要注意的一個(gè)點(diǎn)是JobScheduler所創(chuàng)建并執(zhí)行的人物必須是帶有條件限制的,不然是違背其初衷的,當(dāng)你創(chuàng)建一個(gè)任務(wù)不做任何限制條件并且直接調(diào)用 scheduler.schedule(builder.build());去執(zhí)行該任務(wù)是不可行的,會(huì)報(bào)以下的異常
java.lang.IllegalArgumentException: You're trying to build a job with no constraints, this is not allowed.
其次需要新建一個(gè)service,來繼承JobService(與DreamService類似),而且必須重寫其中的兩個(gè)方法,分別是onStartJob(JobParameters params)和onStopJob(JobParameters params);
客戶端job 的代碼書寫
public class MyJobService extends JobService {
public abstract boolean onStartJob(JobParameters params) { // 在任務(wù)開始執(zhí)行時(shí)觸發(fā)。返回false表示執(zhí)行完畢,返回true表示需要開發(fā)者自己調(diào)用jobFinished方法通知系統(tǒng)已執(zhí)行完成。
...
jobFinished();
}
public abstract boolean onStopJob(JobParameters params){ //在任務(wù)停止執(zhí)行時(shí)觸發(fā)。返回true 為重新調(diào)度,返回false 表示不會(huì)重新調(diào)度,job完全被停止了
...
}
}
當(dāng)上面創(chuàng)建任務(wù)時(shí)執(zhí)行到scheduler.schedule(builder.build()); 則開始準(zhǔn)備執(zhí)行任務(wù),一旦設(shè)置滿足條件,便會(huì)執(zhí)行到onStartJob()方法,也就是在我們的任務(wù)應(yīng)該具體事宜應(yīng)該是放在onStartJob中去做的。
當(dāng)任務(wù)執(zhí)行完畢后要調(diào)用jobFinished()來通知系統(tǒng)。當(dāng)系統(tǒng)受到一個(gè)cancel請(qǐng)求時(shí)會(huì)取消該任務(wù)(當(dāng)該任務(wù)未執(zhí)行將其在pending list刪除,如果該任務(wù)正在執(zhí)行則停止其任務(wù))。
使用Jobscheduler還需要到AndroidManifest.xml中添加一個(gè)service節(jié)點(diǎn)讓你的應(yīng)用擁有綁定和使用這個(gè)JobService的權(quán)限。
<service android:name="com.example.apuser.jobtest.JobTestService"
android:permission="android.permission.BIND_JOB_SERVICE" />
這里需要重點(diǎn)注意的是:這個(gè)job service運(yùn)行在你的主線程,這意味著你需要使用子線程,handler, 或者一個(gè)異步任務(wù)來運(yùn)行耗時(shí)的操作以防止阻塞主線程。
常見接口解釋:
setRequiresBatteryNotLow(boolean) //是否需要電量充足
setRequiresCharging(boolean) //是否需要充電默認(rèn)false
setRequiresDeviceIdle(boolean) //是否需要設(shè)備空閑,設(shè)備空閑是指設(shè)備沒有在使用并且已經(jīng)有一段時(shí)間沒使用了
addTriggerContentUri(TriggerContentUri) //監(jiān)聽指定ContentUri,改變時(shí)才會(huì)觸發(fā)任務(wù),和周期性和持續(xù)性任務(wù)不兼容
setPeriodic(long) //是否是周期性任務(wù),intervalMillis是執(zhí)行的周期,每個(gè)周期最多執(zhí)行一次,和setMinimumLatency和setOverrideDeadline不兼容,flextime = intervaltime
setPeriodic(long intervalMillis, long flexMillis) // flex 時(shí)間為窗口時(shí)間。最小窗口時(shí)間為5分鐘()
setMinimumLatency(long) // 設(shè)置任務(wù)至少延遲多少時(shí)間才執(zhí)行
setOverrideDeadline(long) // 任務(wù)執(zhí)行的截止時(shí)間,如果到了該截止時(shí)間,其他條件不滿足也會(huì)被執(zhí)行
setRequiresStorageNotLow(boolean) //設(shè)置任務(wù)需要存儲(chǔ)空間充裕條件
setPriority(int) // 設(shè)置優(yōu)先級(jí)。越大優(yōu)先級(jí)越高
setPersisted(boolean) // 是否是持續(xù)性任務(wù),如果是,開機(jī)后會(huì)繼續(xù)執(zhí)行,但需要RECEIVE_BOOT_COMPLETED權(quán)限
總結(jié)
JobScheduler 雖然是在5.0上新增加的一個(gè)新服務(wù),但是從L到M,N以及最新的O 上,谷歌Android也是在重點(diǎn)推薦使用該功能,并且在Android O 上谷歌還推出了一套Android vitals 計(jì)劃,旨在提高Android 系統(tǒng)的功耗,性能,以及穩(wěn)定性等相關(guān)指標(biāo),在對(duì)功耗上提出來的建議便是,非精確性的定時(shí)任務(wù)建議使用Job來代替Alarm,能更加準(zhǔn)確的滿足條件的執(zhí)行你想要執(zhí)行的任務(wù)。在Android O上JobScheduler更加完善了其條件控制,加上了低存儲(chǔ),低電量策略下的job運(yùn)行限制,這里將在后面job服務(wù)解析中繼續(xù)提到