一、Service、IntentService、JobIntentService的区别
- Service: 它用于执行某些后台操作的任务,它在主线程上运行,这也是它的缺点。对于主线程上发生的任何长时间运行的操作,建议创建一个新线程并执行该任务(例如; Handler )不会影响主线程的性能。
IntentService : 也是用来完成一些长时间运行的后台任务。唯一的区别是, 它创建一个新线程来执行此任务, 而不在主线程上运行。那么缺点就是: 当应用程序被终止时,提供给IntentService的作业将丢失。
JobIntentService : 与IntentService非常相似, 但JobIntentService是不需要通过startService启动, 而是静态启动的,而且,一旦应用程序重新创建/启动,它可以从头开始启动作业。这句话还需要再考究一下。
从Oreo(Android 8.0)之后, 如果应用程序在后台运行, 则不允许在后台启动服务。Android要求我们通过 content.startForegroundService 而不是 context.startService来启动服务。并且在服务启动后的5s之内, 必须将其绑定到通知, 以使UI元素与之关联,否则就会报错:
android.app.RemoteServiceException
Context.startForegroundService() did not then call Service.startForeground()
那么, 既然知道了原理,是不是直接调用 startForeground(int id, Notification notification) 方法就可以了?
答案是否定的!!
如果IntentService 在启动后(从onStartCommand返回了)被系统杀掉了,在下一次调用Context.startService()之前,不会再创建Service。期间,也不接受空Intent参数的onStartCommand方法调用,因为空的Intent无法进行Service的创建,所以也就未执行IntentService的onCreate、onStart、onHandleIntent方法中的startForeground方法,最后报出以上异常。
所以为了绝对规避这个异常,使用JobIntentService替代IntentService还是可以的,至于为什么??因为它是通过静态方法启动的, 无关乎生命周期,不需要在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来执行。
8.0以上任务被作为job用jobScheduler.enqueue()方法来分发,说到Jobscheduler,应该不陌生了,框架提供的用来APP调度任务的接口,根据APP要求构建JobInfo,系统会在适当的时间调用JobInfo指定的JobService来执行你的任务。
所以在Android8.0及以上JobIntentService和JobService做的事情是相同的,都是等着JobScheduler分配任务来执行。
不同点在于,JobService使用的handler是主线程的Looper,因此需要在onStartJob()中手动创建AsyncTask去执行耗时任务,而JobIntentService则帮我们处理这一过程,使用它只需要写需要做的任务逻辑即可,不用关心卡住主线程的问题。另外,向JobScheduler传递任务操作也更简单了,不需要在指定JobInfo中的参数,直接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问题,通过静态方法就可以启动,还是非常不错的。