Android 9.0:不允许启动服务:应用程序处于后台。。在onResume()之后

Android 9.0:不允许启动服务:应用程序处于后台。。在onResume()之后,android,android-service,android-9.0-pie,Android,Android Service,Android 9.0 Pie,我有一个音乐播放器,它试图在活动的的onResume()中启动服务。为了清晰起见,我删除了几行,但代码实际上是: @Override protected void onResume() { super.onResume(); startService(new Intent(this, MusicService.class)); } 根据崩溃日志,这在一些运行Android p的设备上引发了一个异常: Caused by java.lang.IllegalStateExcept

我有一个音乐播放器,它试图在
活动的
onResume()
中启动
服务。为了清晰起见,我删除了几行,但代码实际上是:

@Override
protected void onResume() {
    super.onResume();

    startService(new Intent(this, MusicService.class));
}
根据崩溃日志,这在一些运行Android p的设备上引发了一个异常:

Caused by java.lang.IllegalStateException: Not allowed to start service Intent { cmp=another.music.player/com.simplecity.amp_library.playback.MusicService }: app is in background uid UidRecord{6a4a9c6 u0a143 TPSL bg:+3m25s199ms idle change:cached procs:1 seq(1283,1283,1283)}
       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 com.simplecity.amp_library.utils.MusicServiceConnectionUtils.bindToService(SourceFile:36)
       at com.simplecity.amp_library.ui.activities.BaseActivity.bindService(SourceFile:129)
       at com.simplecity.amp_library.ui.activities.BaseActivity.onResume(SourceFile:96)
调用
onResume()
(和
super.onResume()
)之后,我的应用程序怎么可能立即出现在后台


这对我来说毫无意义。这可能是一个平台错误吗?所有受此崩溃影响的3500多名用户都在Android P上。

Android.arch.lifecycle是否可以用作此Android 9错误的解决方案

public class MyActivity extends Activity implements LifecycleObserver {

    protected void onResume() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            if (ProcessLifecycleOwner.get().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
                startService(intent);
            } else {
                ProcessLifecycleOwner.get().getLifecycle().addObserver(this);
            }
        } else {
            startService(intent);
        }
    }


    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    void onEnterForeground() {
        startService(intent);
        ProcessLifecycleOwner.get().getLifecycle().removeObserver(this);
    }
}

更新:这在Prod中对我们有效,但不是100%。在过去的一个半月里,我收到了一份撞车报告,如果不是这样的话,可能会有一百多份。在这个问题得到妥善解决之前,这似乎是我们目前最好的选择。也许如果我把时间提高到300以上,那一次碰撞就不会发生了

我们正在测试这一点,到目前为止,这似乎是可行的。将随着我们看到更多结果而更新

class ResumingServiceManager(val lifecycle: Lifecycle) : LifecycleObserver {

    init {
        lifecycle.addObserver(this)
    }

    val disposable: CompositeDisposable = CompositeDisposable()

    fun startService(context: Context, intent: Intent) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            context.startService(intent)
        } else {
            Single.just(true)
                    .delaySubscription(300, TimeUnit.MILLISECONDS)
                    .subscribeOn(AndroidSchedulers.mainThread())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribeBy(
                            onSuccess = {
                                context.startService(intent)
                            }

                    ).addTo(disposable)
        }
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
    fun stopped() {
        disposable.clear()
    }

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    fun destroy() {
        lifecycle.removeObserver(this)
    }
}
class ResumingServiceManager(val生命周期:lifecycle):LifecycleObserver{
初始化{
lifecycle.addObserver(此)
}
val disposable:CompositeDisposable=CompositeDisposable()
趣味startService(上下文:上下文,意图:意图){
if(Build.VERSION.SDK\u INT
onCreate()
中初始化它,然后只要在onResume中调用
resumingServiceManager.startService(此,intent)


它具有生命周期意识,因此当它暂停取消onSuccess触发时,它会清除一次性的,而onSuccess可能会立即打开/关闭到后台。

这已在Android问题跟踪程序中标记为“修复”:

大概这个补丁将在安卓Q的一个版本中发布

据结束这一事件的谷歌人说

有一种解决方法可以避免应用程序崩溃。应用程序可以通过调用
ActivityManager.GetRunningAppProcesss()
Activity.onResume()
中获取进程状态,如果重要性级别低于
ActivityManager.RunningAppProcessInfo.importance\u前台
,则避免启动服务。如果设备尚未完全唤醒,活动将立即暂停,并最终在完全唤醒后再次恢复


谷歌有一个变通办法:

这个问题已经在未来的Android版本中得到了解决

有一种解决方法可以避免应用程序崩溃。应用程序可以获得 通过调用 如果出现以下情况,请避免启动服务 重要性级别低于 ActivityManager.RunningAppProcessInfo.IMPORTANCE\u前台。如果 设备尚未完全唤醒,活动将立即暂停并停止 在它完全清醒后,最终会再次恢复

所以我认为应该是这样的:

// hack for https://issuetracker.google.com/issues/113122354
    List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = activityManager.getRunningAppProcesses();
    if (runningAppProcesses != null) {
        int importance = runningAppProcesses.get(0).importance;
        // higher importance has lower number (?)
        if (importance <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND)
            URLPlayerService.startActionBroadcastServiceData(PlayerActivity.this);
    }

我们队也面临同样的问题。我的日历显示2019年4月5日,但问题仍然在我的三星Galaxy S9+、android 9.0(一个用户界面)上重现

我们在onResume中启动服务,并在Pause中解除绑定

如何复制

当屏幕上显示具有此逻辑的活动时,只需锁定设备,不要触摸10-15分钟。解锁屏幕后,应用程序将崩溃

如何修复

我们找到了实际可行的解决方案。从android 8+开始,在android.os.Handler.post(…)中启动您的服务

示例(Kotlin):

override fun onResume() {
    super.onResume()
    Handler().post {
        val serviceIntent = Intent(activity, SomeService::class.java)
        activity?.startService(serviceIntent)
        activity?.bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE)
    }
}

祝你好运

错误消息似乎模棱两可,我发现消息的最后一部分指的是服务所在的应用程序,而不是试图启动服务并绑定到服务的应用程序

如果服务的应用程序不是前景化的(即使服务本身是后台服务),则会出现错误:

现在,如果我在启动尝试启动服务的“客户端”应用程序之前,运行具有该服务的应用程序,使其位于前台,那么服务启动的一切工作正常

如果该服务是“后台服务”,且该服务的应用程序不在前台,则该服务可能会被终止——因此,如果您需要继续使用该服务,启动该服务实际上是不够的

这似乎是从安卓7到安卓8的变化的结果,在奥利奥,他们开始限制一些东西

上面的Android文档中对此进行了解释


文档中的建议是将您的逻辑迁移到计划的作业中,或者将该服务设置为前台服务,这样可以直观地显示该服务正在运行。

我找到了重现该问题的方法

使用Android 10、11、12 DP2在Android Emulator上测试:

  • Activity.onResume()中启动启动服务的应用程序
  • 按Home(主页)按钮将活动状态更改为stopped(停止)
  • 等到
    override fun onResume() {
        super.onResume()
        Handler().post {
            val serviceIntent = Intent(activity, SomeService::class.java)
            activity?.startService(serviceIntent)
            activity?.bindService(serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE)
        }
    }
    
    W/System.err: java.lang.IllegalStateException: Not allowed to start service Intent { cmp=com.mycompany.myserviceapp/.MyService }: app is in background uid null
            at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1505)
            at android.app.ContextImpl.startService(ContextImpl.java:1461)
            at android.content.ContextWrapper.startService(ContextWrapper.java:644)