Android 9.0:不允许启动服务:app在后台..在onResume()之后

Tim*_*eed 64 android android-service android-9.0-pie

我有一个音乐播放器,试图启动ServiceonResume()的一个Activity.为清晰起见,我删除了几行,但代码有效:

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

    startService(new Intent(this, MusicService.class));
}
Run Code Online (Sandbox Code Playgroud)

根据崩溃日志,这在运行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)
Run Code Online (Sandbox Code Playgroud)

在调用onResume()(和super.onResume())之后,我的应用程序是如何处于后台的?

这对我没有任何意义.这可能是一个平台错误吗?受此次崩溃影响的所有3500多名用户都在Android P.

Mat*_*ski 8

Google提供了一种解决方法:

此问题已在未来的Android版本中解决。

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

所以我认为应该这样:

// 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);
    }
Run Code Online (Sandbox Code Playgroud)

我已经使用处理程序作为解决方法,它的效果很好,但不是100%:

// hack for https://issuetracker.google.com/issues/113122354
   handler.postDelayed(() -> URLPlayerService.startService(PlayerActivity.this),200);
Run Code Online (Sandbox Code Playgroud)

  • 如issuetracker中所述:“活动将立即暂停,并在完全苏醒后再次恢复。” 因此,我认为活动将再次恢复,过程的重要性将变为IMPORTANCE_FOREGROUND。因此不需要处理。是真的吗 (4认同)
  • 上面的“hack”对我有用(注意:在我的案例中,针对此问题报告的所有崩溃均发生在运行 Android 9+ 的三星平台上)。为了完整起见,请在“hack”上方添加以下行来定义 ActivityManager:“ActivityManager ActivityManager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);” (3认同)

Ben*_*654 6

更新:这对我们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)
    }
}
Run Code Online (Sandbox Code Playgroud)

onCreate()初始化它然后随时想要在onResume中启动服务只需调用resumingServiceManager.startService(this, intent)

这是生命周期意识所以它会清除一次性如果它暂停取消onSuccess触发时它可能在前往后台的途中立即打开/关闭.


Tim*_*eed 5

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

据推测,该修复程序将在 Android Q 版本之一中发布。

据关闭问题的谷歌员工说,

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


小智 5

我们的团队面临着同样的问题。我的日历显示 2019 年 4 月 5 日,但问题仍然在我的 Samsung Galaxy S9+、android 9.0(一个 UI)上重现

我们在onResume中启动服务并在onPause中解除绑定。

如何重现

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

怎么修

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

示例(科特林):

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)
    }
}
Run Code Online (Sandbox Code Playgroud)

祝你好运!


小智 -3

也许 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

我在这里找到了。