Wie gehe ich mit Code um, wenn die App durch Wischen in Android getötet wird?

104

Wenn meine App ausgeführt wird und ich die Home-Taste drücke, wird die App im Hintergrund angezeigt. Wenn nun ein langes Drücken der Taste nach Hause und die App töten , indem sie aus der letzten App - Liste klauen, keines der Ereignisse mag onPause(), onStop()oder onDestroy()wird aufgerufen , sondern der Prozess beendet wird. Wie kann ich das tun, wenn ich möchte, dass meine Dienste gestoppt werden, Benachrichtigungen beendet werden und die Registrierung von Listenern aufgehoben wird? Ich habe einige Artikel und Blogs gelesen, aber keine nützlichen Informationen erhalten und keine Dokumentation dazu gefunden. Jede Hilfe wäre dankbar. Danke im Voraus.

CodeWarrior
quelle
Ich löse mein Problem. Check
MysticMagicϡ
@MysticMagic Das funktioniert für einen Dienst. Was ist mit dem Abbrechen von Benachrichtigungen und dem Aufheben der Registrierung von Listenern?
CodeWarrior
Sie können die Registrierung von Listenern in onTaskRemoved aufheben. Kannst du nicht? Und das Gleiche gilt für das Abbrechen von Benachrichtigungen
MysticMagicϡ
@ MysticMagicϡ Was ist, wenn ich beim App-Update das Gleiche tun möchte?
Reji

Antworten:

149

Ich habe gerade ein ähnliches Problem gelöst.

Folgendes können Sie tun, wenn Sie den Dienst nur beenden möchten, wenn die Anwendung durch Wischen aus der Liste der zuletzt verwendeten Apps beendet wird.

In Ihrer Manifest - Datei, halte Flagge stopWithTaskwie truefür Service. Mögen:

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

Aber wenn Sie sagen, Sie möchten die Registrierung von Hörern aufheben und die Benachrichtigung usw. beenden, würde ich diesen Ansatz vorschlagen:

  1. In Ihrer Manifest - Datei, halte Flagge stopWithTaskwie falsefür Service. Mögen:

    <service
        android:name="com.myapp.MyService"
        android:stopWithTask="false" />
  2. MyServiceÜberschreiben Sie jetzt in Ihrem Dienst die Methode onTaskRemoved. (Dies wird nur ausgelöst, wenn eingestellt stopWithTaskist false).

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

Weitere Informationen finden Sie in meiner Frage , die auch einen anderen Teil des Codes enthält.

Hoffe das hilft.

MysticMagicϡ
quelle
Vielen Dank. Überlegen Sie, ob diese Methode verwendet werden könnte, um Swipe-Kills zu identifizieren. Einfacher Blanko-Service?
Kiran
Ja @Kiran können Sie versuchen. :)
MysticMagicϡ
1
@ MysticMagicϡ Hallo, eine Frage, ich habe versucht, Ihre Lösung zu verwenden, aber es scheint, dass lange Vorgänge wie das Senden von Daten an den Server, Analysen an Google usw. manchmal nicht vollständig durchlaufen werden. Könnte es sein, dass der Prozess abgebrochen wird, bevor diese Methode die Möglichkeit hatte, sich vollständig abzuschließen? Haben Sie diese Methode auch auf einem Huawei-Gerät ausprobiert? Es scheint, dass onTaskRemoved auf diesen Geräten niemals aufgerufen wird. Irgendwelche Ideen warum?
Alon Minski
2
@ MysticMagicϡ public void onTaskRemoved (..) Methode nicht in Android O aufrufen. Funktioniert gut in anderen Betriebssystemen, bekommt aber Probleme in Android O.
Jay Patel
2
Dieser Code funktioniert für Android O aufgrund von Einschränkungen des Hintergrunddienstes nicht. Gibt es eine Möglichkeit, dies auf allen Android-Geräten zu handhaben?
Aanal Mehta
33

Ich habe einen Weg gefunden, dies zu tun

mache einen Dienst wie diesen

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) Registrieren Sie diesen Dienst in manifest.xml

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

3) Starten Sie diesen Dienst dann bei Ihrer Splash-Aktivität

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

Und jetzt, wann immer Sie Ihre App von Android löschen, wird diese Methode onTaskRemoved () ausgeführt.

emilpmp
quelle
1
Eins zu eins kopieren und aus dieser Antwort einfügen
Flot2011
17

Ich habe ein ähnliches Problem gelöst. Wenn Sie nach dem Wischen von der letzten Aufgabe und beim nächsten Start ein ordnungsgemäßes Verhalten wünschen, führen Sie die folgenden Schritte aus: -

1) Speichern Sie die Prozess-ID in einer gemeinsamen Einstellung:

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

2) Wenn die Anwendung vom Launcher aus gestartet wird, nachdem die letzte Aufgabe gelöscht wurde, gehen Sie wie folgt vor:

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
quelle
Bestätigt - verwendet auf Android 8 ohne service.onTaskRemoved () - gut gemacht
Gal Rom
4
Diese Lösung erkennt nur, wenn die App neu gestartet wurde, aber Sie können nicht den genauen Zeitpunkt erkennen, zu dem die App getötet wurde
Vadim Kotov
6

Wenn Sie nach Hause drücken - onPauseund onStopIhre Aktivität aufgerufen wird, müssen Sie zu diesem Zeitpunkt alle Einsparungen und Bereinigungen vornehmen, da die Android-Plattform nicht weiter garantiert, dass onDestroyoder eine andere Lebenszyklusmethode aufgerufen wird, sodass der Prozess abgebrochen werden kann ohne Benachrichtigung.

Wüste
quelle
12
Vielen Dank für den Vorschlag, aber ich möchte meine Benachrichtigungen, Dienste und Listener nicht beenden, onPause()und onstop()sie müssen nur beendet werden, wenn der Benutzer die App beendet, dh sich abmeldet.
CodeWarrior
1

Sie müssen Ihre Daten speichern, wenn on onPause()aufgerufen wird. Schauen Sie sich dieses Lebenszyklusdiagramm an: Android Developer

Sie können sehen, dass eine App nach onPause()oder getötet werden kann onStop().

Behandeln Sie Ihre Daten dort und stellen Sie sie in onRestart()\ wieder her onCreate().

Viel Glück!

Fashizel
quelle
1

Sie können Swipe nicht verarbeiten, da das System Ihren Prozess nur aus dem Speicher entfernt, ohne einen Rückruf aufzurufen.

Ich habe überprüft, dass onPause () immer aufgerufen wird, bevor der Benutzer den Bildschirm "Letzte Apps" aufruft. Sie müssen also alle Daten in der onPause-Methode speichern, ohne isFinishing () zu überprüfen.

Verwenden Sie die onBackPressed-Methode, um die Schaltfläche "Zurück" zu aktivieren.

Ahmad
quelle
1
Ich glaube, dies ist die einzig sichere Methode für alle Android-Versionen.
Sergio
@Sergio Ja, es ist die sicherste Methode und ich habe sie in größerem Maßstab getestet.
Ahmad
1

ViewModel.onCleared () kann nützlich sein, wenn das Ziel darin besteht, eine Ressource (möglicherweise ein System, das an einer anderen Stelle im Netzwerk ausgeführt wird) freizugeben, wenn der Benutzer einen Überraschungsexit durch Wischen ausführt, anstatt durch Drücken der Taste "Stopp" oder "Stopp". [So bin ich ursprünglich zu dieser Frage gekommen].

Die Anwendung erhält keine Benachrichtigung und Activity.onDestroy () wird für Konfigurationsänderungen wie z. B. Änderungen der Ausrichtung aufgerufen, sodass die Antwort nicht vorhanden ist. ViewModel.onCleared wird jedoch aufgerufen, wenn die Anwendung entfernt wird (sowie wenn der Benutzer die Aktivität beendet). Wenn die Ressource, die Sie verwenden möchten, mehr als einer Aktivität im Stapel zugeordnet ist, können Sie Referenzzähler oder einen anderen Mechanismus hinzufügen, um zu entscheiden, ob ViewModel.onClear die Ressource freigeben soll.

Dies ist ein weiterer von vielen guten Gründen, ViewModel zu verwenden.

- Bob

Bob Cram
quelle
1

Ich weiß nicht wirklich, warum die oben genannten Ansätze bei meinem Fall nicht funktionieren, obwohl ich android:stopWithTask="false"das onTaskRemoved()nicht aufgerufen habe.

Ein weiterer guter Ansatz wäre die Verwendung AndroidViewModel. Dieser funktioniert sogar in dem Fall, in dem der Benutzer die Anwendung durch Drücken der Zurück-Taste verlässt.

Binden Sie einfach die ViewModelKlasse an Ihre MainActivityund erledigen Sie dann Ihre AufgabeonCleared() .

Beispiel:

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

Binden Sie es dann an Ihre MainActivity:

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

~ Voila!

Droidhs
quelle
Möglicherweise funktioniert es aufgrund von Android O und höher nicht mit dem Service-Ansatz, wie von anderen Kommentatoren erwähnt. Dies scheint eine interessante Lösung zu sein, um hierfür Ansichtsmodelle zu verwenden. Wird dies immer noch ausgelöst, wenn die Anwendung zwangsweise beendet wird (auf dem Bildschirm des App-Umschalters gewischt)? Bearbeiten: Bobs Antwort legt nahe, dass es in diesen Fällen funktioniert
William Reed
ja es funktioniert, das ist der Fall, dem ich begegnet bin
droidhs
0

Das hat bei mir auf Android 6,7,8,9 funktioniert.

Machen Sie einen Dienst wie folgt:

 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) Registrieren Sie diesen Service in manifest.xml:

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

3) Starten Sie diesen Dienst dann bei Ihrer Splash-Aktivität

 startService(new Intent(getBaseContext(),
 OnClearFromRecentService.class));
Alexis Osorio
quelle
1
Und warum läuft Ihr Dienst unter Android 8 und höher weiter? Sie erkennen, dass Started Services nach Android 8 eingeschränkt sind, oder?
Rahil008
0

Wie Bob Cram in seiner Antwort erwähnt hat, ist die onCleared () -Methode von View Model die Antwort. Es funktioniert in beiden Fällen:

  1. Wenn der Benutzer die App entfernt, indem er sie aus dem Hintergrund wischt.
  2. Wenn der Benutzer die gesamte App mit der Schaltfläche Liste löschen löscht.

OnTaskRemoved () des Dienstes funktioniert, wenn der Benutzer die App aus dem Hintergrund wischt, funktioniert jedoch nicht, wenn die Apps mit der Schaltfläche Alle beenden gelöscht werden.

Die onCleared () -Methode von viewModel funktioniert jedoch in beiden Fällen. Sie können if verwenden, um einen laufenden Prozess zu stoppen oder eine Aufgabe auf dem Remote-Server zu löschen.

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