Android 9.0: Запрещено запускать службу: приложение находится в фоновом режиме .. после onResume () - PullRequest
0 голосов
/ 25 августа 2018

У меня есть музыкальный проигрыватель, который пытается запустить Service в onResume() из Activity.Я удалил несколько строк для ясности, но код эффективен:

@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.

Ответы [ 6 ]

0 голосов
/ 05 апреля 2019

наша команда столкнулась с той же проблемой.Мой календарь показывает 5 апреля 2019 года, но проблема все еще воспроизводится на моем Samsung Galaxy S9 +, Android 9.0 (один пользовательский интерфейс)

Мы запускаем службу в onResume и отменяем привязку onPause.

Какдля воспроизведения

Просто заблокируйте устройство, когда на экране присутствует активность с этой логикой, и не трогайте 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)
    }
}

Удачи!

0 голосов
/ 27 марта 2019

Существует обходной путь от Google:

Проблема была решена в будущем выпуске Android.

Существует обходной путь, позволяющий избежать сбоя приложения.Приложения могут получить состояние процесса в Activity.onResume (), вызвав ActivityManager.getRunningAppProcesses () и избежать запуска Service, если уровень важности ниже, чем ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND.Если устройство не полностью проснулось, действия будут немедленно приостановлены и, в конце концов, возобновлены после его полного пробуждения.

Так что я думаю, что так должно быть:

// 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);
    }

Я использовал обработчик как обходной путь, и он работает довольно хорошо, но не на 100%:

// hack for https://issuetracker.google.com/issues/113122354
   handler.postDelayed(() -> URLPlayerService.startService(PlayerActivity.this),200);
0 голосов
/ 26 марта 2019

Это было помечено как 'исправлено' в трекере проблем Android:

Предположительно, исправление будет выпущено в одном из выпусков Android Q.

Согласно Гуглеру, который закрыл вопрос,

Существует обходной путь, позволяющий избежать сбоя приложения. Приложения могут получить состояние процесса в Activity.onResume(), вызвав ActivityManager.getRunningAppProcesses() и избежать запуска Service, если уровень важности ниже ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND. Если устройство не полностью проснулось, действия будут немедленно приостановлены и в конечном итоге возобновлены после его полного пробуждения.

0 голосов
/ 26 марта 2019

Они исправили сбой (в некоторых будущих выпусках, не уверен, какой именно) и предоставили обходной путь: https://issuetracker.google.com/issues/110237673#comment9

0 голосов
/ 10 ноября 2018

ОБНОВЛЕНИЕ: Это работает для нас в 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)
    }
}

В onCreate() инициализируйте его, а затем в любое время, когда вы хотите запустить службу в onResume, просто позвоните resumingServiceManager.startService(this, intent)

Он осведомлен о жизненном цикле, поэтому он удалит одноразовые, если остановится, отменив запуск onSuccess, когда он может оказаться на пути к фону с немедленным открытием / закрытием.

0 голосов
/ 20 октября 2018

Может быть, 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);
    }
}

Я нашел это здесь.

...