在本教程中,您將學(xué)習(xí)如何使用 JobScheduler API適用于 Android Lollipop。當(dāng)滿足一定的條件時(shí),該JobScheduler API允許開發(fā)者創(chuàng)建后臺執(zhí)行的工作。
當(dāng)使用Android進(jìn)行工作時(shí),會遇到這樣的情況——你會想在將來的某個時(shí)間或在一定條件下運(yùn)行任務(wù),例如當(dāng)一個設(shè)備接入電源或連接到Wi-Fi網(wǎng)絡(luò)。值得慶幸的是有API21,因?yàn)锳ndroid Lollipop而被大多數(shù)人所知,谷歌已經(jīng)提供了被稱為JobScheduler API的新組件來處理這樣的情況。
當(dāng)一組預(yù)定義的條件得到滿足時(shí),JobScheduler API的應(yīng)用程序執(zhí)行一項(xiàng)操作。不像 AlarmManager 類,該時(shí)間測定時(shí)不準(zhǔn)確的。此外,該 JobScheduler API 能夠一同批處理各種工作。這允許應(yīng)用程序執(zhí)行特定的任務(wù),同時(shí)考慮設(shè)備的電池在定時(shí)控制上的成本。
在這篇文章中,通過使用JobScheduler API和 jobservice 類在一個Android應(yīng)用程序中運(yùn)行一個簡單的后臺任務(wù),您將學(xué)習(xí)更多關(guān)于 JobScheduler API和 jobservice 類方面的知識。在本教程中的代碼可以在 GitHub上獲得。
開始,你會想使用最小所需的API 21創(chuàng)建一個新的Android項(xiàng)目,因?yàn)樵贏ndroid的最新版本中已經(jīng)增加了JobScheduler API ,在寫作的時(shí)候, 它沒有通過支持庫向后兼容。
假設(shè)你使用的是Android Studio,在你點(diǎn)擊完新項(xiàng)目按鈕后,你會看到一個基本的“Hello World”應(yīng)用。你要進(jìn)行這個項(xiàng)目的第一步是創(chuàng)建一個新的Java類。為了讓事情簡單化,命名它為JobSchedulerService ,并擴(kuò)展jobservice 類,這就需要創(chuàng)建兩個方法:onStartJob(JobParameters params) 和onStopJob(JobParameters params)。
public class JobSchedulerService extends JobService {
@Override
public boolean onStartJob(JobParameters params) {
return false;
}
@Override
public boolean onStopJob(JobParameters params) {
return false;
}
}
當(dāng)你開始你的任務(wù)時(shí),onstartjob(jobparameters params) 是你必須使用的方法,因?yàn)樗窍到y(tǒng)用來觸發(fā)已經(jīng)安排的工作的。正如你可以看到,該方法返回一個布爾值。如果返回值是false,該系統(tǒng)假定任何任務(wù)運(yùn)行不需要很長時(shí)間并且到方法返回時(shí)已經(jīng)完成。如果返回值是true,那么系統(tǒng)假設(shè)任務(wù)是需要一些時(shí)間并且負(fù)擔(dān)落到你(開發(fā)者)的身上,當(dāng)給定的任務(wù)完成時(shí)通過調(diào)用jobFinished(JobParameters params, boolean needsRescheduled)告知系統(tǒng)。
當(dāng)收到取消請求時(shí),onStopJob(JobParameters params) 是系統(tǒng)用來取消掛起的任務(wù)的。重要的是要注意到,如果onStartJob(JobParameters params)返回 false,當(dāng)取消請求被接收時(shí),該系統(tǒng)假定沒有目前運(yùn)行的工作。換句話說,它根本就不調(diào)用onStopJob(JobParameters params)。
有一點(diǎn)要注意的是,工作服務(wù)在你的應(yīng)用程序的主線程上運(yùn)行。這意味著,你必須使用另一個線程處理程序,或運(yùn)行時(shí)間更長的任務(wù)異步任務(wù)以不阻塞主線程。由于多線程技術(shù)超出本教程的范圍,讓我們保持簡單和實(shí)現(xiàn)處理程序來運(yùn)行在JobSchedulerService類中的任務(wù)。
private Handler mJobHandler = new Handler( new Handler.Callback() {
@Override
public boolean handleMessage( Message msg ) {
Toast.makeText( getApplicationContext(),
"JobService task running", Toast.LENGTH_SHORT )
.show();
jobFinished( (JobParameters) msg.obj, false );
return true;
}
} );
在處理程序中,你執(zhí)行handleMessage(Message msg)方法(Handler實(shí)例的一部分),并使用它運(yùn)行你的任務(wù)的邏輯。在此情況下,讓事情簡單化,從應(yīng)用程序發(fā)送一個Toast信息,雖然這是在那里你可以像同步數(shù)據(jù)一樣給出你的邏輯。
當(dāng)任務(wù)完成時(shí),你需要調(diào)用jobFinished(JobParameters params, boolean needsRescheduled)讓系統(tǒng)知道你完成了那項(xiàng)任務(wù),它可以開始排隊(duì)接下來的操作。如果你不這樣做,你的工作將只運(yùn)行一次,你的應(yīng)用程序?qū)⒉槐辉试S執(zhí)行額外的工作。
在onStartJob(JobParameters params)方法中,jobFinished(JobParameters params, boolean needsRescheduled) 的兩個參數(shù)值是JobParameters傳遞到JobService類,一個布爾值讓系統(tǒng)知道是否需要根據(jù)工作的最初要求重新編排工作。這個布爾值對于理解是非常有用的,因?yàn)樗鼛椭懔私馊绾翁幚碛捎谄渌麊栴}(如一個失敗的網(wǎng)絡(luò)電話)而導(dǎo)致你的任務(wù)無法完成的情況。
隨著Handler程序?qū)嵗膭?chuàng)建,你可以繼續(xù)并開始執(zhí)行onStartJob(JobParameters params)和onStopJob(JobParameters params)方法來控制你的任務(wù)。你會發(fā)現(xiàn),在下面的代碼片段中,onStartJob(JobParameters params)方法的返回值為true。這是因?yàn)?,你要使用一個Handler 程序?qū)嵗齺砜刂颇愕牟僮?,這意味著相比onStartJob(JobParameters params)方法它可能需要更長的時(shí)間來完成。通過返回true,你讓應(yīng)用程序知道,你將手動調(diào)用jobFinished(JobParameters params, boolean needsRescheduled)方法。你也會注意到,數(shù)字1被傳遞到Handler示例。這是相關(guān)引用工作中你將用到的標(biāo)識符。
@Override
public boolean onStartJob(JobParameters params) {
mJobHandler.sendMessage( Message.obtain( mJobHandler, 1, params ) );
return true;
}
@Override
public boolean onStopJob(JobParameters params) {
mJobHandler.removeMessages( 1 );
return false;
}
一旦你使用Java部分的JobSchedulerService類完成,你需要研究AndroidManifest.xml,并增加服務(wù)節(jié)點(diǎn),因此,你的應(yīng)用程序有權(quán)限綁定和使用JobService類。
<service android:name=".JobSchedulerService"
android:permission="android.permission.BIND_JOB_SERVICE" />
隨著JobSchedulerService 類完成,我們可以開始考慮你的應(yīng)用程序?qū)⑷绾闻cJobScheduler API相互作用。你需要做的第一件事就是創(chuàng)建一個JobScheduler對象,在示例代碼中調(diào)用mJobScheduler ,通過獲得一個系統(tǒng)服務(wù)的實(shí)例JOB_SCHEDULER_SERVICE來初始化它。在示例應(yīng)用程序中,這是在MainActivity 類中完成的。
mJobScheduler = (JobScheduler)
getSystemService( Context.JOB_SCHEDULER_SERVICE );
當(dāng)你想創(chuàng)建你的計(jì)劃任務(wù)時(shí),你可以使用來JobInfo.Builder創(chuàng)建一個JobInfo對象,字符指針傳遞到你的服務(wù)中。為了創(chuàng)建一個JobInfo對象,JobInfo.Builder 接受兩個參數(shù)。第一個參數(shù)是你將運(yùn)行工作的標(biāo)識符,第二個參數(shù)是你將與JobScheduler API.一同使用的服務(wù)的組件名稱。
JobInfo.Builder builder = new JobInfo.Builder( 1,
new ComponentName( getPackageName(),
JobSchedulerService.class.getName() ) );
當(dāng)你的工作將執(zhí)行時(shí),這個編輯器可以讓你設(shè)置許多不同的控制選項(xiàng)。下面的代碼片段顯示了你如何設(shè)置你的任務(wù)每三秒定期運(yùn)行一次。
builder.setPeriodic( 3000 );
其他方法包括:
setMinimumLatency(long minLatencyMillis):這會使你的工作不啟動直到規(guī)定的毫秒數(shù)已經(jīng)過去了。這是與setPeriodic(long time)不兼容的,并且如果同時(shí)使用這兩個函數(shù)將會導(dǎo)致拋出異常。
setOverrideDeadline(long maxExecutionDelayMillis):這將設(shè)置你的工作期限。即使是無法滿足其他要求,你的任務(wù)將約在規(guī)定的時(shí)間已經(jīng)過去時(shí)開始執(zhí)行。類似于setMinimumLatency(long time),這個函數(shù)是與 setPeriodic(long time) 互相排斥的,并且如果同時(shí)使用這兩個函數(shù),將會導(dǎo)致拋出異常。setPersisted(boolean isPersisted):這個函數(shù)告訴系統(tǒng),在設(shè)備重新啟動后,你的任務(wù)是否應(yīng)該繼續(xù)存在。
setRequiredNetworkType(int networkType):這個函數(shù)會告訴你工作,只有在設(shè)備處于一種特定的網(wǎng)絡(luò)中時(shí),它才啟動。它的默認(rèn)值是JobInfo.NETWORK_TYPE_NONE,這就意味著,無論是否有網(wǎng)絡(luò)連接,該任務(wù)均可以運(yùn)行。另外兩個可用的類型是JobInfo.NETWORK_TYPE_ANY,這需要某種類型的網(wǎng)絡(luò)連接可用,工作才可以運(yùn)行;以及JobInfo.NETWORK_TYPE_UNMETERED,這就要求設(shè)備在非蜂窩網(wǎng)絡(luò)中。
setRequiresCharging(boolean requiresCharging):使用這個函數(shù)會告訴你的應(yīng)用程序,除非設(shè)備開始充電,否則工作不會啟動。
setRequiresDeviceIdle(boolean requiresDeviceIdle):這會告知你的工作不會啟動,除非用戶不使用他們的設(shè)備,并且他們已經(jīng)有一段時(shí)間沒有使用它。重要的是要注意到,setRequiredNetworkType(int networkType)、setRequiresCharging(boolean requireCharging)和setRequiresDeviceIdle(boolean requireIdle)可能會導(dǎo)致你的工作永遠(yuǎn)不啟動,除非setOverrideDeadline(long time)還設(shè)置允許即使不符合條件的情況下,你的工作也可以運(yùn)行。一旦規(guī)定優(yōu)先條件,你可以創(chuàng)建JobInfo對象,并發(fā)送它到你的JobScheduler對象,如下所示。
if( mJobScheduler.schedule( builder.build() ) <= 0 ) {
//If something goes wrong
}
你會注意到,schedule操作返回一個整數(shù)。如果schedule 失敗,它將返回一個為零或更少的值,對應(yīng)于一個錯誤代碼。否則,它將返回在JobInfo.Builder中定義的作業(yè)標(biāo)識符。
如果你的應(yīng)用程序需要你停止特定或所有工作,你可以通過對JobScheduler 對象調(diào)用cancel(int jobId)或cancelAll()實(shí)現(xiàn)。
mJobScheduler.cancelAll();
你現(xiàn)在應(yīng)該能夠使用JobScheduler API以及你自己的應(yīng)用程序進(jìn)行批處理工作和運(yùn)行后臺操作。
在這篇文章中,你已經(jīng)學(xué)會了如何實(shí)現(xiàn)一個子類,使用一個Handler對象來運(yùn)行你的應(yīng)用程序的后臺任務(wù)。你也學(xué)會了如何使用JobInfo.Builder來設(shè)置你的服務(wù)應(yīng)該運(yùn)行時(shí)的要求。通過這些,你應(yīng)該能夠在留意功率消耗的同時(shí),提高你自己的應(yīng)用程序操作。