一、Service、IntentService、JobIntentService的區(qū)別
- Service: 它用于執(zhí)行某些后臺操作的任務,它在主線程上運行,這也是它的缺點。對于主線程上發(fā)生的任何長時間運行的操作,建議創(chuàng)建一個新線程并執(zhí)行該任務(例如; Handler )不會影響主線程的性能。
IntentService : 也是用來完成一些長時間運行的后臺任務。唯一的區(qū)別是, 它創(chuàng)建一個新線程來執(zhí)行此任務, 而不在主線程上運行。那么缺點就是: 當應用程序被終止時,提供給IntentService的作業(yè)將丟失。
JobIntentService : 與IntentService非常相似, 但JobIntentService是不需要通過startService啟動, 而是靜態(tài)啟動的,而且,一旦應用程序重新創(chuàng)建/啟動,它可以從頭開始啟動作業(yè)。這句話還需要再考究一下。
從Oreo(Android 8.0)之后, 如果應用程序在后臺運行, 則不允許在后臺啟動服務。Android要求我們通過 content.startForegroundService 而不是 context.startService來啟動服務。并且在服務啟動后的5s之內, 必須將其綁定到通知, 以使UI元素與之關聯(lián),否則就會報錯:
android.app.RemoteServiceException
Context.startForegroundService() did not then call Service.startForeground()
那么, 既然知道了原理,是不是直接調用 startForeground(int id, Notification notification) 方法就可以了?
答案是否定的??!
如果IntentService 在啟動后(從onStartCommand返回了)被系統(tǒng)殺掉了,在下一次調用Context.startService()之前,不會再創(chuàng)建Service。期間,也不接受空Intent參數(shù)的onStartCommand方法調用,因為空的Intent無法進行Service的創(chuàng)建,所以也就未執(zhí)行IntentService的onCreate、onStart、onHandleIntent方法中的startForeground方法,最后報出以上異常。
所以為了絕對規(guī)避這個異常,使用JobIntentService替代IntentService還是可以的,至于為什么??因為它是通過靜態(tài)方法啟動的, 無關乎生命周期,不需要在5s之內調用 startForeground(int id, Notification notification)。
//InitIntentService為JobIntentService子類名稱
InitIntentService.enqueueWork(context, new Intent());
?
?
二、JobIntentService和JobService的對比
先看一下JobIntentService的官方文檔:
Helper for processing work that has been enqueued for a job/service. When running on {@link android.os.Build.VERSION_CODES#O Android O} or later, the work will be dispatched as a job via {@link android.app.job.JobScheduler#enqueue JobScheduler.enqueue}. When running on older versions of the platform, it will use {@link android.content.Context#startService Context.startService}.
官方文檔解釋為,用于處理被加入到job或service任務的一個輔助工具,8.0以下被當作普通的Intent使用startSerivce()啟動service來執(zhí)行。
8.0以上任務被作為job用jobScheduler.enqueue()方法來分發(fā),說到Jobscheduler,應該不陌生了,框架提供的用來APP調度任務的接口,根據(jù)APP要求構建JobInfo,系統(tǒng)會在適當?shù)臅r間調用JobInfo指定的JobService來執(zhí)行你的任務。
所以在Android8.0及以上JobIntentService和JobService做的事情是相同的,都是等著JobScheduler分配任務來執(zhí)行。
不同點在于,JobService使用的handler是主線程的Looper,因此需要在onStartJob()中手動創(chuàng)建AsyncTask去執(zhí)行耗時任務,而JobIntentService則幫我們處理這一過程,使用它只需要寫需要做的任務邏輯即可,不用關心卡住主線程的問題。另外,向JobScheduler傳遞任務操作也更簡單了,不需要在指定JobInfo中的參數(shù),直接enqueue(context,intent)就可以。
這有點像Service和IntentService的關系。
?
三、JobIntentService的使用
1、在Manifest中聲名Permission
<uses-permission android:name="android.permission.WAKE_LOCK" />
2、在Manifest中聲名Service
<service android:name=".InitIntentService"
android:permission="android.permission.BIND_JOB_SERVICE" />
3、繼承JobIntentService類
public class InitIntentService extends JobIntentService {
public static final int JOB_ID = 1;
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, InitIntentService.class, JOB_ID, work);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
// 具體邏輯
}
}
4、啟動JobIntentService子類
InitIntentService.enqueueWork(context, new Intent());
JobIntentService不需要關心JobIntentService的生命周期,不需要startService()方法,也就避免了開頭中的crash問題,通過靜態(tài)方法就可以啟動,還是非常不錯的。
?
?
?
?
?
?