Come gestire il codice quando l'app viene interrotta scorrendo in Android?


104

Se la mia app è in esecuzione e premo il pulsante Home, l'app va in background. Ora, se premuto a lungo il tasto home e uccidere l'applicazione scorrendo dalla recente lista di app, nessuno degli eventi come onPause(), onStop()o onDestroy()viene chiamato piuttosto il processo è terminato. Quindi, se voglio che i miei servizi si interrompano, uccidano le notifiche e annulli la registrazione dei listener, come posso farlo? Ho letto parecchi articoli e blog ma non ho ricevuto alcuna informazione utile e non ho trovato alcuna documentazione al riguardo. Qualsiasi aiuto sarebbe apprezzato. Grazie in anticipo.


Risolvo il mio problema. Check
MysticMagicϡ

@MysticMagic Funziona per un servizio, che dire dell'annullamento delle notifiche e dell'annullamento della registrazione degli ascoltatori?
CodeWarrior

Puoi annullare la registrazione dei listener in onTaskRemoved. Non puoi? E lo stesso per l'annullamento delle notifiche
MysticMagicϡ

@ MysticMagicϡ E se volessi fare le stesse cose durante l'aggiornamento dell'app?
reji

Risposte:


150

Ho appena risolto un problema simile.

Ecco cosa puoi fare se si tratta solo di interrompere il servizio quando l'applicazione viene interrotta scorrendo dall'elenco delle app recenti.

All'interno del file Manifest, mantieni il flag stopWithTaskcome trueper Service. Piace:

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

Ma poiché dici di voler annullare la registrazione degli ascoltatori e interrompere la notifica, ecc., Suggerirei questo approccio:

  1. All'interno del file Manifest, mantieni il flag stopWithTaskcome falseper Service. Piace:

    <service
        android:name="com.myapp.MyService"
        android:stopWithTask="false" />
  2. Ora nel tuo MyServiceservizio, sovrascrivi il metodo onTaskRemoved. (Questo verrà attivato solo se stopWithTaskè impostato su false).

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

Fai riferimento alla mia domanda per maggiori dettagli, che contiene anche altre parti di codice.

Spero che questo ti aiuti.


Grazie. Pensando se questo metodo potesse essere utilizzato per identificare le uccisioni con scorrimento. Semplice servizio in bianco?
Kiran

Sì @Kiran puoi provare. :)
MysticMagicϡ

1
@ MysticMagicϡ ciao, una domanda, ho provato a utilizzare la tua soluzione, ma sembra che operazioni lunghe come l'invio di dati al server, le analisi a Google ecc. Alcune volte non riescano a completare il processo. Potrebbe essere che il processo venga interrotto prima che questo metodo abbia la possibilità di completarsi completamente? Anche tu hai provato questo metodo su un dispositivo Huawei? Sembra che onTaskRemoved non venga mai chiamato su quei dispositivi. Qualche idea sul perché?
Alon Minski

2
@ MysticMagicϡ public void onTaskRemoved (..) Il metodo non si chiama in Android O. Funziona bene in altri sistemi operativi ma si verifica un problema in Android O.
Jay Patel

2
Questo codice non funziona per Android O a causa della limitazione del servizio in background. C'è un modo per gestirlo in tutti i dispositivi Android?
Aanal Mehta

33

Trovato un modo per farlo

fare un servizio come questo

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) registra questo servizio in manifest.xml

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

3) Quindi avvia questo servizio sulla tua attività splash

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

E ora ogni volta che cancellerai la tua app da Android recente, verrà eseguito questo metodo onTaskRemoved ().


1
Copia e incolla uno a uno da questa risposta: stackoverflow.com/questions/21040339
Flot2011

17

Ho risolto un problema simile. Se vuoi che dopo aver fatto scorrere il dito dall'attività recente e al successivo avvio si comporti correttamente, segui i passaggi seguenti: -

1) Salva l'ID del processo nella preferenza condivisa:

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

2) Quando l'applicazione viene avviata dal programma di avvio dopo essere stata cancellata dall'attività recente, eseguire:

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
}

Confermato - utilizzato su Android 8 senza service.onTaskRemoved () - ben fatto
Gal Rom

4
Questa soluzione rileva solo se l'app è stata riavviata, ma non è possibile rilevare il momento esatto in cui l'app è stata interrotta
Vadim Kotov

6

Quando premi home - onPausee la onStoptua attività viene chiamata, quindi in questo momento devi fare tutti i risparmi e la pulizia, perché la piattaforma Android non garantisce ulteriormente che onDestroyverrà richiamato o qualsiasi altro metodo del ciclo di vita, quindi il processo potrebbe essere interrotto senza alcuna notifica.


12
Grazie per il suggerimento, ma non voglio uccidere le mie notifiche, servizi e ascoltatori, onPause()e onstop()devono essere uccisi solo quando l'utente esce dall'app, ovvero disconnettersi.
CodeWarrior

1

È necessario salvare i dati quando onPause()viene chiamato on. Guarda questo diagramma del ciclo di vita: Sviluppatore Android

Puoi vedere che un'app può essere interrotta dopo onPause()o onStop().

Gestisci i tuoi dati lì e recuperali in onRestart()\ onCreate().

in bocca al lupo!


1

Non puoi gestire lo swipe, perché il sistema rimuove semplicemente il tuo processo dalla memoria senza chiamare alcuna richiamata.

Ho verificato che prima che l'utente chiami la schermata "app recenti", onPause () verrà sempre chiamato. Quindi è necessario salvare tutti i dati nel metodo onPause senza controllare isFinishing ().

Per controllare il pulsante Indietro, utilizzare il metodo onBackPressed.


1
Credo che questo sia l'unico metodo sicuro per tutte le versioni di Android.
Sergio

@Sergio sì, è il metodo più sicuro e l'ho testato su un'applicazione più ampia.
Ahmad

1

ViewModel.onCleared () può essere utile, se l'obiettivo è quello di rilasciare una risorsa (forse un sistema in esecuzione da qualche altra parte sulla rete) quando l'utente esegue un'uscita a sorpresa scorrendo, invece che premendo il pulsante "stop" o. [È così che sono arrivato originariamente a questa domanda].

L'applicazione non riceve una notifica e Activity.onDestroy () viene chiamata per modifiche alla configurazione come le modifiche all'orientamento, quindi la risposta non è lì. Ma ViewModel.onCleared viene chiamato quando l'applicazione viene rimossa (così come quando l'utente si ritira dall'attività). Se la risorsa che si desidera utilizzare è associata a più di un'attività nello stack, è possibile aggiungere conteggi dei riferimenti o qualche altro meccanismo per decidere se ViewModel.onClear deve rilasciare la risorsa.

Questo è un altro dei tanti buoni motivi per usare ViewModel.

- Bob


1

Non so davvero perché gli approcci di cui sopra non funzionano sul mio caso anche se l'ho impostato android:stopWithTask="false"come onTaskRemoved()non chiamato.

Un altro buon approccio sarebbe usare AndroidViewModel. Questo funziona anche nel caso in cui l'utente esce dall'applicazione premendo il pulsante Indietro.

Collega semplicemente la ViewModelclasse alla tua, MainActivityquindi esegui la onCleared()richiamata.

Esempio:

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

quindi collegalo alla tua MainActivity:

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

~ Voilà!


potrebbe non funzionare con l'approccio al servizio a causa di Android O e sopra, come menzionato da altri commentatori. Questa sembra una soluzione interessante per utilizzare i modelli di visualizzazione per questo. Viene comunque attivato se l'applicazione viene interrotta forzatamente (strisciata nella schermata del selettore di app)? modifica: la risposta di Bob suggerisce che funziona in questi casi
William Reed

sì, funziona, questo è il caso in cui mi sono
imbattuto

0

Questo ha funzionato per me su Android 6,7,8,9.

Crea un servizio come questo:

 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) Registra questo servizio in manifest.xml:

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

3) Quindi avvia questo servizio sulla tua attività splash

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

1
E perché il tuo servizio continuerà a funzionare su Android 8 e versioni successive? Ti rendi conto che ci sono restrizioni sui servizi avviati dopo Android 8, giusto?
rahil008

0

Come ha detto Bob Cram nella sua risposta, il metodo onCleared () di View Model è la risposta. Funziona in entrambi i casi:

  1. Quando l'utente rimuove l'app scorrendo l'app dallo sfondo.
  2. Quando l'utente cancella tutta l'app utilizzando il pulsante Cancella elenco.

Il servizio onTaskRemoved () funzionerà quando l'utente fa scorrere l'app dallo sfondo, ma non funzionerà quando le app vengono cancellate utilizzando il pulsante kill all.

Ma il metodo onCleared () di viewModel funziona in entrambi i casi. È possibile utilizzare if per interrompere qualsiasi processo in corso o cancellare qualsiasi attività nel server remoto.

 override fun onCleared() {
        super.onCleared()
        Log.d(TAG , "App Killed")
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.