studio - Android 9.0: No se permite iniciar el servicio: la aplicación está en segundo plano... después de onResume()
reiniciar una activity (6)
Tengo un reproductor de música que intenta iniciar un
Service
en
onResume()
de una
Activity
.
He eliminado algunas líneas para mayor claridad, pero el código es efectivamente:
@Override
protected void onResume() {
super.onResume();
startService(new Intent(this, MusicService.class));
}
De acuerdo con los registros de fallos, esto está lanzando una excepción en algunos dispositivos que ejecutan 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)
¿Cómo es posible que mi aplicación esté en segundo plano, inmediatamente después de
onResume()
(y
super.onResume()
)?
Esto no tiene ningún sentido para mí. ¿Podría ser esto un error de plataforma? Todos los más de 3500 usuarios afectados por este bloqueo están en Android P.
¿Tal vez android.arch.lifecycle podría usarse como una solución para este error de 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);
}
}
ACTUALIZACIÓN: Esto está funcionando para nosotros en Prod, pero no es 100%. Recibí un informe de colisión en el último mes y medio, de lo contrario habría sido más de cien. Hasta que esto se arregle adecuadamente, esta parece ser nuestra mejor opción por ahora. Tal vez si aumentara el tiempo más allá de los 300, ¿ese choque nunca hubiera ocurrido?
Estamos probando esto ahora mismo, que hasta ahora parece estar funcionando. Se actualizará a medida que veamos más 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)
}
}
En
onCreate()
y luego, en cualquier momento que desee iniciar un servicio en onResume, simplemente llame a resumingServiceManager.startService
resumingServiceManager.startService(this, intent)
Es consciente del ciclo de vida, por lo que eliminará el desechable si hace una pausa en la cancelación de la activación de onSuccess cuando podría estar en el camino hacia el fondo con una apertura / cierre inmediato.
Arreglaron la falla (en una versión futura, no estoy seguro de cuál exactamente) y proporcionaron una solución por ahora: https://issuetracker.google.com/issues/110237673#comment9
Esto se ha marcado como ''arreglado'' en el Rastreador de problemas de Android:
Presumiblemente, la solución se publicará en uno de los lanzamientos de Android Q.
Según el Googler que cerró el tema,
Hay una solución para evitar la caída de la aplicación. Las aplicaciones pueden obtener el estado del proceso en
Activity.onResume()
llamando aActivityManager.getRunningAppProcesses()
y evitan iniciar el servicio si el nivel de importancia es menor queActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND
. Si el dispositivo no está completamente despierto, las actividades se detendrían de inmediato y, finalmente, se reanudarán después de que esté completamente despierto.
Hay una solución de Google:
El problema ha sido abordado en el futuro lanzamiento de Android.
Hay una solución para evitar la caída de la aplicación. Las aplicaciones pueden obtener el estado del proceso en Activity.onResume () llamando a ActivityManager.getRunningAppProcesses () y evitan iniciar el servicio si el nivel de importancia es menor que ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND. Si el dispositivo no está completamente despierto, las actividades se detendrían de inmediato y, finalmente, se reanudarán después de que esté completamente despierto.
Así que creo que debería gustar eso:
// 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);
}
He utilizado el manejador como solución alternativa y funciona bastante bien, pero no al 100%:
// hack for https://issuetracker.google.com/issues/113122354
handler.postDelayed(() -> URLPlayerService.startService(PlayerActivity.this),200);
Nuestro equipo se enfrentó con el mismo problema. Mi calendario muestra el 5 de abril de 2019, pero el problema aún se reproduce en mi Samsung Galaxy S9 +, Android 9.0 (una interfaz de usuario)
Iniciamos el servicio en onResume y desenlazamos onPause.
Como reproducirse
Simplemente bloquee su dispositivo, cuando la actividad con esta lógica está en la pantalla, y no la toque entre 10 y 15 minutos. Después de desbloquear la pantalla, la aplicación se bloqueará.
Como arreglar
Encontramos una solución que realmente funciona. Desde Android 8+, inicie su servicio en android.os.Handler.post (...)
Ejemplo (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)
}
}
¡Buena suerte!