Heute wollte ich Ihnen einen anderen Ansatz zur Aufrechterhaltung des Zustands bei der Entwicklung von Android-Anwendungen vorstellen. Es ist kein Geheimnis, dass unsere Anwendung im Hintergrund jederzeit beendet werden kann, und dieses Problem wird mit der EinfĂŒhrung aggressiver Energieeinsparungen immer dringlicher - hallo
Oreo . AuĂerdem hat niemand die KonfigurationsĂ€nderung am Telefon abgebrochen: Ausrichtung, SprachĂ€nderung usw. Und um die Anwendung im Hintergrund zu öffnen und die BenutzeroberflĂ€che im letzten Zustand anzuzeigen, mĂŒssen wir uns darum kĂŒmmern, sie zu speichern. Oh, das
onSaveInstanceState .

Wie viel Schmerz hat er uns gebracht.
Ich werde spÀter Beispiele mit
Clean Achitecture und
Dagger2 geben , seien Sie also darauf vorbereitet :)
Das Problem der Aufrechterhaltung des Zustands in AbhÀngigkeit von Aufgaben kann auf verschiedene Arten gelöst werden:
- Speichern Sie PrimĂ€rdaten in onSaveInstanceState des Hosts (AktivitĂ€t, Fragment) - wie z. B. die Seitenkennung , den Benutzer und was auch immer. Was wir fĂŒr die anfĂ€ngliche Datenerfassung und Seitenanzeige benötigen.
- Speichern Sie die empfangenen Daten im interaktiven Programm im Repository (SharedPreference, Database).
- Verwenden Sie Rethein-Fragmente, um Daten bei der Neuerstellung von AktivitÀten zu speichern und wiederherzustellen.
Aber was ist, wenn wir den Status der BenutzeroberflĂ€che sowie die aktuelle Reaktion der BenutzeroberflĂ€che auf Benutzeraktionen wiederherstellen mĂŒssen? Betrachten wir der Einfachheit halber die Lösung dieses Problems anhand eines realen Beispiels. Wir haben eine Anmeldeseite - der Benutzer gibt seine Daten ein, klickt auf die SchaltflĂ€che und erhĂ€lt dann einen eingehenden Anruf. Unsere Bewerbung tritt in den Hintergrund. Das System tötet ihn. Klingt beĂ€ngstigend, nicht wahr?)
Der Benutzer kehrt zur Anwendung zurĂŒck und was sollte er sehen? Setzen Sie mindestens den Anmeldevorgang fort und zeigen Sie den Fortschritt an. Wenn sich die Anwendung vor dem Aufrufen der onDestroy-Methode des Hosts anmelden konnte, wird dem Benutzer die Navigation zum Startbildschirm der Anwendung angezeigt. Dieses Verhalten kann mit der Zustandsmaschine leicht gelöst werden. Sehr guter
Bericht von Yandex . Im selben Artikel werde ich versuchen, meine gekauten Gedanken zu diesem Bericht zu teilen.
Nun ein kleiner Code:
Basisstaatpublic interface BaseState<VIEW extends BaseView, OWNER extends BaseOwner> extends Parcelable{ @NonNull String getName(); void onEnter(@NonNull VIEW aView); void onExit(); void forward(); void back(); void invalidateView(@NonNull VIEW aView); @NonNull OWNER getOwner(); void setOwner(@NonNull OWNER aOwner); }
Baseoverner public interface BaseOwner<VIEW extends BaseView, STATE extends BaseState> extends BasePresenter<VIEW>{ void setState(@NonNull STATE aState); }
BasestateImpl public abstract class BaseStateImpl<VIEW extends BaseView, OWNER extends BaseOwner> implements BaseState<VIEW, OWNER>{ private OWNER mOwner; @NonNull @Override public String getName(){ return getClass().getName(); } @Override public void onEnter(@NonNull final VIEW aView){ Timber.d( getName()+" onEnter");
In unserem Fall ist der StaatseigentĂŒmer ein Moderator.
Auf der Anmeldeseite können drei eindeutige ZustÀnde unterschieden werden:
LoginInitState ,
LoginProgressingState ,
LoginCompleteState .
Ăberlegen Sie nun, was in diesen Staaten passiert.
LoginInitState Wir haben die Validierung von Feldern und im Falle einer erfolgreichen Validierung wird die Login-SchaltflÀche aktiv.
In
LoginProgressingState wird eine
Anmeldeanforderung gestellt , ein Token wird gespeichert, zusÀtzliche Anforderungen werden gestellt, um die HauptaktivitÀt der Anwendung zu starten.
LoginCompleteState navigiert zum Hauptbildschirm der Anwendung.
Bedingt kann der Ăbergang zwischen ZustĂ€nden im folgenden Diagramm dargestellt werden:

Der
Status LoginProgressingState wird beendet, wenn der Anmeldevorgang im
Status LoginCompleteState erfolgreich ist und
LoginInitState fehlschlĂ€gt . Wenn sich unsere Sichtweise löst, haben wir also einen völlig deterministischen Zustand des PrĂ€sentators. Wir mĂŒssen diesen Status mit dem Standard-Android-Mechanismus
onSaveInstanceState speichern . Dazu mĂŒssen alle Anmeldestatus die
Parcelable- Schnittstelle implementieren. Daher erweitern wir unsere Basisschnittstelle
BaseState .
Als nĂ€chstes haben wir eine Frage, wie dieser Status vom Moderator an unseren Gastgeber weitergeleitet werden kann. Am einfachsten ist es, den PrĂ€sentator vom Host nach Daten zu fragen. Aus architektonischer Sicht sieht dies jedoch nicht sehr gut aus. Und so kommen uns Fragmente zu Hilfe. Wir können eine Schnittstelle fĂŒr den Cache erstellen und in diesem Fragment implementieren:
public interface Cache{ void saveCacheData(@Nullable Parcelable aData); @Nullable Parcelable getCacheData(); boolean isCacheExist(); }
Als nĂ€chstes injizieren wir das Cache-Fragment wie Cache in den Konstruktor des Interaktors. Wir fĂŒgen dem Integrator Methoden hinzu, um den Status im Cache abzurufen und zu speichern. Jetzt können wir bei jeder Ănderung des Status des PrĂ€sentators den Status im Interaktor speichern, und der Interaktor speichert seinerseits im Cache. Alles wird sehr logisch. Beim erstmaligen Laden des Hosts empfĂ€ngt der PrĂ€sentator den Status vom Interaktor, der wiederum Daten aus dem Cache empfĂ€ngt. So sieht die StatusĂ€nderungsmethode im PrĂ€sentator aus:
@Override public void setState(@NonNull final LoginBaseState aState){ mState.onExit(); mState = aState; clearDisposables(); mState.setOwner(this); mState.onEnter(getView()); mInteractor.setState(mState); }
Ich möchte auf diesen Punkt hinweisen: Das Speichern von Daten ĂŒber den Cache kann fĂŒr alle Daten erfolgen, nicht nur fĂŒr den Status. Möglicherweise mĂŒssen Sie Ihren eigenen eindeutigen Snippet-Cache erstellen, um aktuelle Daten zu speichern. Dieser Artikel beschreibt einen allgemeinen Ansatz. Ich möchte auch darauf hinweisen, dass die fragliche Situation sehr ĂŒbertrieben ist. Im Leben muss man Probleme viel komplizierter lösen. In unserer Anwendung wurden beispielsweise drei Seiten kombiniert: Anmeldung, Registrierung, Kennwortwiederherstellung. In diesem Fall war das Zustandsdiagramm wie folgt:

Mithilfe des im Artikel beschriebenen Statusmusters und Ansatzes konnten wir den Code lesbarer und wartbarer machen. Wichtig ist, den aktuellen Status der Anwendung wiederherzustellen.
Der vollstÀndige Code kann
im Repository angezeigt werden.