@KaMyLL是对的。 我的应用程序遇到了同样的问题,可以通过用JobIntentService替换IntentService(我们已经在onTokenRefresh()启动onTokenRefresh()来解决它。
因为我发现JobScheduler和JobIntentService文档有点令人困惑,我想用一些代码片段来解决所有问题。 我希望这能使每个人都清楚这个问题。
是什么导致了这个问题?
由于Android 8的新背景执行限制 ,当应用程序可能处于后台时,您不应再启动后台服务:
当应用程序位于前台时,它可以自由地创建和运行前台和后台服务。 当应用程序进入后台时,它有一个几分钟的窗口,在该窗口中仍然允许创建和使用服务。 在该窗口的末尾,该应用程序被视为空闲。 此时,系统会停止应用程序的后台服务,就像应用程序已调用服务的Service.stopSelf()方法一样。
并且:
在许多情况下,您的应用可以使用JobScheduler作业替换后台服务。
因此,对于Android 7.x及更低版本,当应用程序处于后台时使用startService()(据我所知)没问题。 但在Android 8中,这会导致崩溃。 因此,您现在应该使用JobScheduler 。 JobScheduler和IntentService之间的行为差异是立即执行IntentService。 另一方面,不能保证立即执行排入JobScheduler的作业。 Android操作系统将确定何时有一个好的时间点,以便更节能。 所以可能会有延迟。 到目前为止,我不知道这需要多长时间。 因此,一种解决方案可能是检查操作系统版本并使用if-else分支您的代码。 幸运的是,支持库帮助我们以更优雅的方式解决这个问题,而无需复制任何代码: JobIntentService ,它基本上是为您做的。
如何重现这个问题?
上面的第一个引用声明该应用程序仍然“有一个几分钟的窗口,它仍然允许创建和使用服务。” ,因此,为了重现和调试问题(使用Firebase中的onTokenRefresh()示例),您可以在使用startService()启动服务之前设置断点。 关闭应用程序并在那里等待5-10分钟。 继续执行,您将看到此问题的IllegalStateException 。 能够将问题重现为基础,以确保我们的修复能够真正解决问题。
如何将我的IntenService迁移到JobIntentService?
我使用FirebaseInstanceIdService.onTokenRefresh()作为示例:
a)将BIND_JOB_SERVICE权限添加到您的服务:
android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"/>
b)不是从IntentService扩展,只需从android.support.v4.app.JobIntentService扩展,将onHandleIntent(Intent)方法重命名为onHandleWork(Intent) ,并添加一个enqueueWork(Context,Intent)方便的函数:
public class FcmRegistrationJobIntentService extends JobIntentService
{
// Unique job ID for this service.
static final int JOB_ID = 42;
// Convenience method for enqueuing work in to this service.
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, FcmRegistrationJobIntentService.class, JOB_ID, work);
}
@Override
protected void onHandleWork(@NonNull Intent intent) {
// the code from IntentService.onHandleIntent() ...
}
}
c)使用enqueueWork()方便的函数启动作业:
public class ComfyFirebaseInstanceIdService extends FirebaseInstanceIdService {
@Override
public void onTokenRefresh() {
Intent intent = new Intent(this, FcmRegistrationJobIntentService.class);
// startService(intent);
FcmRegistrationJobIntentService.enqueueWork(this, intent);
}
}
我希望这个例子很有帮助。 至少在执行了这些步骤之后,我无法再在我的Android 8设备上重现该问题,并且它继续使用我的Android 7设备。
更新
在不推荐使用FirebaseInstanceIdService我们应该从代码中删除它,并使用FirebaseMessagingService onNewToken代替。