startService能够很便利的发动一个service服务,也能够运转在独自的进程。

但是如果在后台调用了startService,则很可能会抛出一个崩溃。

Caused by: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.test.broadservice/.MyService }: app is in background uid UidRecord{b67c471 u0a86 RCVR idle change:uncached procs:1 seq(0,0,0)}
        at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1577)
        at android.app.ContextImpl.startService(ContextImpl.java:1532)
        at android.content.ContextWrapper.startService(ContextWrapper.java:664)
        at android.content.ContextWrapper.startService(ContextWrapper.java:664)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1661) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:193) 
        at android.app.ActivityThread.main(ActivityThread.java:6669) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 

过错原因

Android8.0之后,体系增加了对后台Service的约束,如果运用处于后台,调用startService会抛出IllegalStateException

意思是,在后台的运用,不允许调用startService发动一个后台服务,否则就会抛出反常。

解决办法

1. 运用startForegroundService

运用办法比较简单,这儿就不列出代码了。

有几点需求注意:

  • 用此办法发动前台服务,会在用户的告诉栏上显示
  • 必须在5s内调用服务的startForeground办法,否则会发生ANR
2. 运用JobScheduler

运用JobScheduler能够完成在后台运转使命。

界说一个JobService:

public class MyJobService extends JobService {
    @Override
    public boolean onStartJob(JobParameters params) {
        return false;
    }
    @Override
    public boolean onStopJob(JobParameters params) {
        return false;
    }
}

onStartJob

  • 运转在主进程,需求避免履行耗时的操作。
  • 回来true:表明使命还在继续履行
  • 回来false:表明使命已履行完
  • 履行完之后,能够调jobFinished办法来告诉体系使命已完结。

onStopJob:

  • 当条件不满足的时分,会回调这个办法。
  • 回来true:表明条件满足时,再次履行使命
  • 回来false:表明使命完全完毕

注册JobService

        <service
            android:name=".MyJobService"
            android:permission="android.permission.BIND_JOB_SERVICE" />

界说一个JobInfo

JobInfo.Builder builder = new JobInfo.Builder(111, new ComponentName(this, MyJobService.class));
// todo 设置使命的参数

将使命发布给体系:

JobScheduler jobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
jobScheduler.schedule(builder.build());
3. 运用WorkManager

WorkManagerJobScheduler的升级版本,且支撑多进程,能够将使命运转到独自的进程中。详细运用办法能够参考之前的文章:运用退出后继续运转后台使命,来试试WorkManager吧!

总结

Android 8.0版本以上,在后台调用startService会抛出IllegalStateException反常,需求改用其他的方法来运用。

常用的办法有如下三种:

  • startForegroundService: 这种方法会在用户的告诉栏显示UI。
  • JobScheduler:能够完成后台无感知运转使命。
  • WorkManagerJetpack里的库,JobScheduler的升级版,支撑多进程。