Erstens weiß ich, dass man eine Anwendung auf Android nicht wirklich beenden sollte. In meinem Anwendungsfall möchte ich meine Anwendung in einem bestimmten Fall auf die Werkseinstellungen zurücksetzen, in dem ein Server bestimmte Informationen an den Client sendet.
Der Benutzer kann nur mit EINER Instanz der Anwendung am Server angemeldet sein (dh mehrere Geräte sind nicht zulässig). Wenn eine andere Instanz diese "angemeldete" Sperre erhält, müssen alle anderen Instanzen dieses Benutzers ihre Daten löschen (auf die Werkseinstellungen zurücksetzen), um die Konsistenz aufrechtzuerhalten.
Es ist möglich, die Sperre zwangsweise zu erhalten, da der Benutzer die App möglicherweise löschen und neu installieren kann, was zu einer anderen Instanz-ID führen würde und der Benutzer die Sperre nicht mehr aufheben kann. Daher ist es möglich, das Schloss gewaltsam zu bekommen.
Aufgrund dieser Kraftmöglichkeit müssen wir immer in einer konkreten Instanz überprüfen, ob sie das Schloss hat. Dies geschieht bei (fast) jeder Anfrage an den Server. Der Server sendet möglicherweise eine "falsche Sperr-ID". Wenn dies erkannt wird, muss die Clientanwendung alles löschen.
Das war der Anwendungsfall.
Ich habe ein ActivityA, das das Login ActivityL oder das Haupt- ActivityB der App abhängig von einem sharedPrefs-Wert startet. Nach dem Start von L oder B schließt es sich so, dass nur L oder B läuft. Für den Fall, dass der Benutzer bereits angemeldet ist, wird B jetzt ausgeführt.
B startet C. C fordert startServicedas IntentServiceD. Das ergibt diesen Stapel:
(A)> B> C> D.
Von der onHandleIntent-Methode von D wird ein Ereignis an einen ResultReceiver R gesendet .
R behandelt dieses Ereignis jetzt, indem es dem Benutzer einen Dialog zur Verfügung stellt, in dem er die Anwendung auf die Werkseinstellungen zurücksetzen kann (Löschen der Datenbank, sharedPrefs usw.).
Nach dem Zurücksetzen auf die Werkseinstellungen möchte ich die Anwendung neu starten (um alle Aktivitäten zu schließen) und erst wieder A starten, das dann das Login ActivityL startet und sich selbst beendet:
(A)> L.
Die onClick-Methode des Dialogs sieht folgendermaßen aus:
@Override
public void onClick(DialogInterface dialog, int which) {
// Will call onCancelListener
MyApplication.factoryReset(); // (Deletes the database, clears sharedPrefs, etc.)
Intent i = new Intent(MyApp.getContext(), A.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MyApp.getContext().startActivity(i);
}
Und das ist die MyAppKlasse:
public class MyApp extends Application {
private static Context context;
@Override
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
public static Context getContext() {
return context;
}
public static void factoryReset() {
// ...
}
}
Das Problem ist, wenn ich FLAG_ACTIVITY_NEW_TASKdie Aktivitäten B und C verwende, laufen sie noch. Wenn ich beim Anmelden auf die Schaltfläche "Zurück" drücke, wird ActivityC angezeigt, ich möchte jedoch zum Startbildschirm zurückkehren.
Wenn ich das nicht einstelle, FLAG_ACTIVITY_NEW_TASKerhalte ich den Fehler:
07-07 12:27:12.272: ERROR/AndroidRuntime(9512): android.util.AndroidRuntimeException: Calling startActivity() from outside of an Activity context requires the FLAG_ACTIVITY_NEW_TASK flag. Is this really what you want?
Ich kann die Aktivitäten nicht verwenden Context, da das ServiceIntentD möglicherweise auch von einer Hintergrundaufgabe aufgerufen wird, die von der gestartet wird AlarmManager.
Wie könnte ich das lösen, damit der Aktivitätsstapel (A)> L wird?