¿Cómo manejar el código cuando la aplicación se mata al deslizar en Android?

104

Si mi aplicación se está ejecutando y presiono el botón de inicio, la aplicación pasa a segundo plano. Ahora, si mantienes presionado el botón de inicio y matas la aplicación deslizándola desde la lista de aplicaciones recientes, ninguno de los eventos como onPause(), onStop()o onDestroy()es llamado, el proceso finaliza. Entonces, si quiero que mis servicios se detengan, eliminen las notificaciones y anulen el registro de los oyentes, ¿cómo puedo hacerlo? Leí bastantes artículos y blogs, pero no obtuve ninguna información útil y no encontré ninguna documentación al respecto. Cualquier ayuda sería apreciada. Gracias por adelantado.

CodeWarrior
fuente
Resuelvo mi problema. Check
MysticMagicϡ
@MysticMagic Eso funciona para un servicio, ¿qué pasa con la cancelación de notificaciones y la eliminación del registro de oyentes?
CodeWarrior
Puede anular el registro de los oyentes en onTaskRemoved. No puedes? Y lo mismo para cancelar notificaciones
MysticMagicϡ
@ MysticMagicϡ ¿Qué pasa si quiero hacer lo mismo en la actualización de la aplicación?
reji

Respuestas:

150

Acabo de resolver un problema similar.

Esto es lo que puede hacer si solo se trata de detener el servicio cuando la aplicación se mata al deslizar el dedo desde la lista de aplicaciones recientes.

Dentro de su archivo de manifiesto, mantenga la bandera stopWithTaskcomo truepara Servicio. Me gusta:

<service
    android:name="com.myapp.MyService"
    android:stopWithTask="true" />

Pero como dice que desea anular el registro de los oyentes y detener la notificación, etc., sugeriría este enfoque:

  1. Dentro de su archivo de manifiesto, mantenga la bandera stopWithTaskcomo falsepara Servicio. Me gusta:

    <service
        android:name="com.myapp.MyService"
        android:stopWithTask="false" />
  2. Ahora a su MyServiceservicio, método de anulación onTaskRemoved. (Esto se disparará solo si stopWithTaskestá configurado en false).

    public void onTaskRemoved(Intent rootIntent) {
    
        //unregister listeners
        //do any other cleanup if required
    
        //stop service
        stopSelf();  
    }

Consulte mi pregunta para obtener más detalles, que también contiene otra parte del código.

Espero que esto ayude.

MysticMagicϡ
fuente
Gracias. Pensando si este método podría usarse para identificar muertes por deslizamiento. ¿Servicio simple en blanco?
Kiran
Sí @ Kiran, puedes intentarlo. :)
MysticMagicϡ
1
@ MysticMagicϡ hola, una pregunta, traté de usar su solución, pero parece que las operaciones largas como enviar datos al servidor, análisis a google, etc., algunas veces fallan hasta el final. ¿Podría ser que el proceso se elimine antes de que este método tenga la oportunidad de completarse completamente? ¿También ha probado este método en un dispositivo Huawei? Parece que onTaskRemoved nunca se llama en esos dispositivos. ¿Alguna idea de por qué?
Alon Minski
2
@ MysticMagicϡ public void onTaskRemoved (..) El método no llama en Android O. Funciona bien en otros sistemas operativos pero tiene problemas en Android O.
Jay Patel
2
Este código no funciona para Android O debido a la limitación del servicio en segundo plano. ¿Hay alguna forma de manejar esto en todos los dispositivos Android?
Aanal Mehta
33

Encontré una forma de hacer esto

hacer un servicio como este

public class OnClearFromRecentService extends Service {

@Override
public IBinder onBind(Intent intent) {
    return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Log.d("ClearFromRecentService", "Service Started");
    return START_NOT_STICKY;
}

@Override
public void onDestroy() {
    super.onDestroy();
    Log.d("ClearFromRecentService", "Service Destroyed");
}

@Override
public void onTaskRemoved(Intent rootIntent) {
    Log.e("ClearFromRecentService", "END");
    //Code here
    stopSelf();
}

}

2) registre este servicio en manifest.xml

<service android:name="com.example.OnClearFromRecentService" android:stopWithTask="false" />

3) Luego inicie este servicio en su actividad de bienvenida

startService(new Intent(getBaseContext(), OnClearFromRecentService.class));

Y ahora, cada vez que borre su aplicación de Android reciente, se ejecutará este método onTaskRemoved ().

emilpmp
fuente
1
Copie y pegue uno a uno de esta respuesta: stackoverflow.com/questions/21040339
Flot2011
17

Resolví un problema similar. Si desea que después de deslizar el dedo desde una tarea reciente y en el próximo lanzamiento, se comporte correctamente, siga los pasos a continuación:

1) Guarde el ID del proceso en preferencia compartida:

SharedPreferencesUtils.getInstance().putInt(SharedPreferencesUtils.APP_PROCESS_ID, android.os.Process.myPid());

2) Cuando la aplicación se inicia desde el iniciador después de borrar la tarea reciente, haga lo siguiente:

int previousProcessID = mSharedPreferencesUtils.getInt(SharedPreferencesUtils.APP_PROCESS_ID);

int currentProcessID = android.os.Process.myPid();

if ((previousProcessID == currentProcessID)) {
    // This ensures application not killed yet either by clearing recent or anyway
} else {
    // This ensures application killed either by clearing recent or by anyother means
}
Anshul Agarwal
fuente
Confirmado - usado en Android 8 sin service.onTaskRemoved () - muy bien hecho
Gal Rom
4
Esta solución solo detecta si la aplicación se reinició, pero no puede detectar el momento exacto en que se eliminó la aplicación
Vadim Kotov
6

Cuando presiona Inicio, onPausey onStopse está llamando a su Actividad, por lo que en este momento debe hacer todos los ahorros y la limpieza, porque la plataforma Android no garantiza que onDestroyse invoque o cualquier otro método del ciclo de vida, por lo que el proceso podría ser eliminado sin ninguna notificación.

Desierto
fuente
12
Gracias por la sugerencia, pero no quiero eliminar mis notificaciones, servicios y oyentes, onPause()y onstop()deben eliminarse solo cuando el usuario sale de la aplicación, es decir, cierra la sesión.
CodeWarrior
1

Necesita guardar sus datos cuando onPause()se llama a. Mira este diagrama de ciclo de vida: Desarrollador de Android

Puede ver que una aplicación se puede eliminar después de onPause()o onStop().

Maneje sus datos allí y recupérelos en onRestart()\ onCreate().

¡buena suerte!

Fashizel
fuente
1

No puede manejar el deslizamiento, porque el sistema simplemente elimina su proceso de la memoria sin llamar a ninguna devolución de llamada.

He comprobado que antes de que el usuario llame a la pantalla de "aplicaciones recientes", siempre se llamará a onPause (). Por lo tanto, debe guardar todos los datos en el método onPause sin marcar isFinishing ().

Para comprobar el botón de retroceso, utilice el método onBackPressed.

Ahmad
fuente
1
Creo que este es el único método seguro para todas las versiones de Android.
Sergio
@Sergio, sí, es el método más seguro y lo probé en una aplicación a mayor escala.
Ahmad
1

ViewModel.onCleared () puede ser útil si el objetivo es liberar algún recurso (tal vez un sistema que se ejecuta en otro lugar de la red) cuando el usuario ejecuta una salida sorpresa deslizando el dedo, en lugar de presionar el botón "detener". [Así es como llegué originalmente a esta pregunta].

La aplicación no recibe una notificación y Activity.onDestroy () recibe una llamada para cambios de configuración, como cambios en la orientación, por lo que la respuesta no está ahí. Pero se llama a ViewModel.onCleared cuando la Aplicación se elimina (así como cuando el usuario se retira de la actividad). Si el recurso que desea usar está asociado con más de una actividad en la pila, puede agregar recuentos de referencias o algún otro mecanismo para decidir si ViewModel.onClear debería liberar el recurso.

Esta es otra de las muchas buenas razones para usar ViewModel.

-- Beto

Bob Cram
fuente
1

Realmente no sé por qué los enfoques anteriores no funcionan en mi caso, incluso si configuré android:stopWithTask="false"que onTaskRemoved()no se llamó.

Otro buen enfoque sería utilizar AndroidViewModel. Este incluso funciona en el caso cuando el usuario sale de la aplicación al presionar el botón Atrás.

Simplemente vincule la ViewModelclase a su y MainActivityluego haga su onCleared()devolución de llamada de tarea .

Ejemplo:

public class MainViewModel extends AndroidViewModel {
    public MainViewModel(@NonNull Application application) {
        super(application);
    }

    @Override
    protected void onCleared() {
        // Do your task here
        Log.e("MainViewModel", "OnCleared mainViewModel");
        super.onCleared();
    }
}

luego vincúlelo a su MainActivity:

MainViewModel viewModel = new ViewModelProvider(this).get(MainViewModel.class);

~ ¡Voila!

droides
fuente
Es posible que no funcione con el enfoque de servicio debido a Android O y superior, como lo mencionaron otros comentaristas. Esta parece una solución interesante para utilizar modelos de vista para esto. ¿Esto aún se activa si la aplicación se mata a la fuerza (se desliza en la pantalla del conmutador de aplicaciones)? editar: la respuesta de Bob sugiere que funciona en estos casos
William Reed
sí, funciona, ese es el caso con el que me
encontré
0

Esto funcionó para mí en Android 6,7,8,9.

Haz un servicio como este:

 public class OnClearFromRecentService extends Service {

 @Override public IBinder onBind(Intent intent) {
     return null; }

 @Override public int onStartCommand(Intent intent, int flags, int
 startId) {
     Log.d("ClearFromRecentService", "Service Started");
     return START_NOT_STICKY; }

 @Override public void onDestroy() {
     super.onDestroy();
     Log.d("ClearFromRecentService", "Service Destroyed"); }

 @Override public void onTaskRemoved(Intent rootIntent) {
     Log.e("ClearFromRecentService", "END");
     //Code here
     stopSelf(); } }

2) Registre este servicio en manifest.xml:

<service android:name="com.example.OnClearFromRecentService"
 android:stopWithTask="false" />

3) Luego inicie este servicio en su actividad de bienvenida

 startService(new Intent(getBaseContext(),
 OnClearFromRecentService.class));
Alexis Osorio
fuente
1
¿Y por qué su servicio seguirá funcionando en Android 8 y superior? Te das cuenta de que hay restricciones en los servicios iniciados posteriores a Android 8, ¿verdad?
rahil008
0

Como Bob Cram mencionó en su respuesta, el método onCleared () de View Model es la respuesta. Funciona en ambos casos:

  1. Cuando el usuario elimina la aplicación deslizando la aplicación desde el fondo.
  2. Cuando el usuario borra toda la aplicación usando el botón de borrar lista.

El servicio onTaskRemoved () funcionará cuando el usuario deslice la aplicación desde el fondo, pero no funcionará cuando las aplicaciones se borren con el botón de matar a todos.

Pero el método onCleared () de viewModel funciona en ambos casos. Puede usar si para detener cualquier proceso en curso o borrar cualquier tarea en el servidor remoto.

 override fun onCleared() {
        super.onCleared()
        Log.d(TAG , "App Killed")
    }
Utkarsh Singh
fuente