edition - firmware android pie




Android 9.0: Não é permitido iniciar o serviço: app está em segundo plano.. after onResume() (4)

Eu tenho um player de música que tenta iniciar um Service em onResume() de uma Activity . Eu removi algumas linhas para maior clareza, mas o código é efetivamente:

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

    startService(new Intent(this, MusicService.class));
}

De acordo com os registros de falhas, isso gera uma exceção em alguns dispositivos que executam o 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)

Como é possível que meu aplicativo esteja em segundo plano, imediatamente depois de onResume() (e super.onResume() ) ser chamado?

Isso não faz nenhum sentido para mim. Isso poderia ser um bug da plataforma? Todos os 3500+ usuários afetados por esse acidente estão no Android P.


ATUALIZAÇÃO: Isso está funcionando para nós no Prod, mas não é 100%. Recebi um relatório de acidente no último mês e meio, quando haveria bem mais de cem anos. Até que isso seja corrigido corretamente, essa parece ser a melhor opção por enquanto. Talvez se eu aumentasse o tempo além de 300 que um acidente nunca teria acontecido?

Estamos testando isso agora, o que parece estar funcionando. Vai atualizar conforme vemos mais resultados

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

Em onCreate() inicializá-lo e sempre que você quiser iniciar um serviço em onResume basta chamar resumingServiceManager.startService resumingServiceManager.startService(this, intent)

Ele está ciente do ciclo de vida, portanto, limpará o descartável se ele pausar o cancelamento do onSuccess de ser acionado quando estiver no caminho para o segundo plano com um abrir / fechar imediato.



Isso foi marcado como "fixo" no rastreador de problemas do Android:

Presumivelmente, a correção será lançada em um dos lançamentos do Android Q.

De acordo com o Googler que fechou a questão,

Há uma solução alternativa para evitar a falha do aplicativo. Os aplicativos podem obter o estado do processo em Activity.onResume() chamando ActivityManager.getRunningAppProcesses() e evitam iniciar o Serviço se o nível de importância for menor que ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND . Se o dispositivo não estiver totalmente ativado, as atividades serão pausadas imediatamente e, eventualmente, serão retomadas novamente depois que estiverem totalmente ativadas.


Talvez android.arch.lifecycle poderia ser usado como uma solução para este bug do 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);
    }
}

Eu encontrei aqui.





android-9.0-pie