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