Wie deklariere ich globale Variablen in Android?


595

Ich erstelle eine Anwendung, für die eine Anmeldung erforderlich ist. Ich habe die Haupt- und die Anmeldeaktivität erstellt.

In der Hauptaktivitätsmethode habe onCreateich die folgende Bedingung hinzugefügt:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    ...

    loadSettings();
    if(strSessionString == null)
    {
        login();
    }
    ...
}

Die onActivityResultMethode, die ausgeführt wird, wenn das Anmeldeformular beendet wird, sieht folgendermaßen aus:

@Override
public void onActivityResult(int requestCode,
                             int resultCode,
                             Intent data)
{
    super.onActivityResult(requestCode, resultCode, data);
    switch(requestCode)
    {
        case(SHOW_SUBACTICITY_LOGIN):
        {
            if(resultCode == Activity.RESULT_OK)
            {

                strSessionString = data.getStringExtra(Login.SESSIONSTRING);
                connectionAvailable = true;
                strUsername = data.getStringExtra(Login.USERNAME);
            }
        }
    }

Das Problem ist, dass das Anmeldeformular manchmal zweimal angezeigt wird (die login()Methode wird zweimal aufgerufen), und auch wenn die Telefontastatur verschoben wird, wird das Anmeldeformular erneut angezeigt, und ich denke, das Problem ist die Variable strSessionString.

Weiß jemand, wie die Variable global festgelegt wird, um zu vermeiden, dass das Anmeldeformular angezeigt wird, nachdem sich der Benutzer bereits erfolgreich authentifiziert hat?


Ein gutes Tutorial zum Umgang mit einem Aktivitätsstatus mithilfe des Bundles für gespeicherte Instanzzustände. quicktips.in/…
Deepak Swami

Antworten:


954

Ich habe diese Antwort bereits '09 geschrieben, als Android noch relativ neu war und es in der Android-Entwicklung viele nicht gut etablierte Bereiche gab. Ich habe am Ende dieses Beitrags einen langen Nachtrag hinzugefügt, in dem einige Kritikpunkte angesprochen und eine philosophische Meinungsverschiedenheit über die Verwendung von Singletons anstelle der Unterklassifizierung von Application beschrieben werden. Lesen Sie es auf eigenes Risiko.

URSPRÜNGLICHE ANTWORT:

Das allgemeinere Problem, auf das Sie stoßen, ist das Speichern des Status über mehrere Aktivitäten und alle Teile Ihrer Anwendung hinweg. Eine statische Variable (z. B. ein Singleton) ist eine gängige Java-Methode, um dies zu erreichen. Ich habe jedoch festgestellt, dass eine elegantere Möglichkeit in Android darin besteht, Ihren Status mit dem Anwendungskontext zu verknüpfen.

Wie Sie wissen, ist jede Aktivität auch ein Kontext, der Informationen über ihre Ausführungsumgebung im weitesten Sinne enthält. Ihre Anwendung hat auch einen Kontext, und Android garantiert, dass sie in Ihrer Anwendung als einzelne Instanz vorhanden ist.

Um dies zu tun, erstellen Sie eine eigene Unterklasse von android.app.Application und geben diese Klasse im Anwendungs-Tag in Ihrem Manifest an. Jetzt erstellt Android automatisch eine Instanz dieser Klasse und stellt sie für Ihre gesamte Anwendung zur Verfügung. Sie können von jedem contextmit der Context.getApplicationContext()Methode darauf zugreifen ( Activitybietet auch eine Methode getApplication(), die genau den gleichen Effekt hat). Das Folgende ist ein extrem vereinfachtes Beispiel mit folgenden Einschränkungen:

class MyApp extends Application {

  private String myState;

  public String getState(){
    return myState;
  }
  public void setState(String s){
    myState = s;
  }
}

class Blah extends Activity {

  @Override
  public void onCreate(Bundle b){
    ...
    MyApp appState = ((MyApp)getApplicationContext());
    String state = appState.getState();
    ...
  }
}

Dies hat im Wesentlichen den gleichen Effekt wie die Verwendung einer statischen Variablen oder eines Singletons, lässt sich jedoch recht gut in das vorhandene Android-Framework integrieren. Beachten Sie, dass dies nicht prozessübergreifend funktioniert (sollte Ihre App eine der seltenen mit mehreren Prozessen sein).

Aus dem obigen Beispiel ist etwas zu beachten. Angenommen, wir hätten stattdessen etwas getan wie:

class MyApp extends Application {

  private String myState = /* complicated and slow initialization */;

  public String getState(){
    return myState;
  }
}

Jetzt wird diese langsame Initialisierung (wie das Schlagen der Festplatte, das Schlagen des Netzwerks, alles Blockieren usw.) jedes Mal durchgeführt, wenn die Anwendung instanziiert wird! Sie denken vielleicht, das ist nur einmal für den Prozess und ich muss die Kosten trotzdem bezahlen, oder? Wie Dianne Hackborn weiter unten erwähnt, ist es beispielsweise durchaus möglich, dass Ihr Prozess instanziiert wird, um ein Hintergrund-Broadcast-Ereignis zu verarbeiten. Wenn Ihre Broadcast-Verarbeitung diesen Status nicht benötigt, haben Sie möglicherweise nur eine ganze Reihe komplizierter und langsamer Vorgänge umsonst ausgeführt. Lazy Instantiation ist hier der Name des Spiels. Das Folgende ist eine etwas kompliziertere Art der Anwendung, die für alles andere als die einfachste Verwendung sinnvoller ist:

class MyApp extends Application {

  private MyStateManager myStateManager = new MyStateManager();

  public MyStateManager getStateManager(){
    return myStateManager ;
  }
}

class MyStateManager {

  MyStateManager() {
    /* this should be fast */
  }

  String getState() {
    /* if necessary, perform blocking calls here */
    /* make sure to deal with any multithreading/synchronicity issues */

    ...

    return state;
  }
}

class Blah extends Activity {

  @Override
  public void onCreate(Bundle b){
    ...
    MyStateManager stateManager = ((MyApp)getApplicationContext()).getStateManager();
    String state = stateManager.getState();
    ...
  }
}

Während ich die Anwendungsunterklasse der Verwendung von Singletons als elegantere Lösung vorziehe, würde ich Entwickler lieber Singletons verwenden, wenn dies wirklich notwendig ist, als überhaupt nicht über die Leistung und die Multithreading-Auswirkungen der Zuordnung des Status zur Anwendungsunterklasse nachzudenken.

ANMERKUNG 1: Wie anticafe kommentiert hat, ist in der Manifestdatei ein Tag erforderlich, um Ihre Anwendungsüberschreibung korrekt mit Ihrer Anwendung zu verknüpfen. Weitere Informationen finden Sie in den Android-Dokumenten. Ein Beispiel:

<application
     android:name="my.application.MyApp" 
     android:icon="..."
     android:label="...">
</application>

HINWEIS 2: user608578 fragt unten, wie dies mit der Verwaltung nativer Objektlebenszyklen funktioniert. Ich bin nicht im geringsten in der Lage, nativen Code mit Android zu verwenden, und ich bin nicht qualifiziert zu beantworten, wie dies mit meiner Lösung interagieren würde. Wenn jemand eine Antwort darauf hat, bin ich bereit, sie gutzuschreiben und die Informationen in diesen Beitrag zu setzen, um maximale Sichtbarkeit zu gewährleisten.

NACHTRAG:

Wie einige Leute bemerkt haben, ist dies keine Lösung für einen anhaltenden Zustand, was ich in der ursprünglichen Antwort vielleicht mehr hätte betonen sollen. Das heißt, dies ist keine Lösung zum Speichern von Benutzer- oder anderen Informationen, die über die gesamte Lebensdauer der Anwendung hinweg beibehalten werden sollen. Daher halte ich die meisten Kritikpunkte im Zusammenhang mit Anwendungen, die zu irgendeinem Zeitpunkt getötet werden, usw. für strittig, da alles, was jemals auf der Festplatte gespeichert werden musste, nicht über eine Anwendungsunterklasse gespeichert werden sollte. Es soll eine Lösung zum Speichern des temporären, leicht wiederherstellbaren Anwendungsstatus (unabhängig davon, ob ein Benutzer angemeldet ist) und von Komponenten sein, die eine einzelne Instanz (z. B. Application Network Manager) ( NICHT Singleton!) Sind.

Dayerman war so freundlich, auf ein interessantes Gespräch mit Reto Meier und Dianne Hackborn hinzuweisen, in dem von der Verwendung von Anwendungsunterklassen zugunsten von Singleton-Mustern abgeraten wird. Somatik hat auch schon früher auf etwas Ähnliches hingewiesen, obwohl ich es damals nicht gesehen habe. Aufgrund der Rolle von Reto und Dianne bei der Wartung der Android-Plattform kann ich nicht nach Treu und Glauben empfehlen, ihre Ratschläge zu ignorieren. Was sie sagen, geht. Ich möchte den Meinungen nicht zustimmen, die in Bezug auf die Bevorzugung von Singleton gegenüber Anwendungsunterklassen geäußert wurden. In meiner Meinungsverschiedenheit werde ich Konzepte verwenden, die am besten in dieser StackExchange-Erklärung des Singleton-Entwurfsmusters erläutert werden, damit ich in dieser Antwort keine Begriffe definieren muss. Ich empfehle dringend, den Link zu überfliegen, bevor Sie fortfahren. Punkt für Punkt:

Dianne erklärt: "Es gibt keinen Grund, eine Unterklasse aus der Anwendung zu erstellen. Es ist nicht anders als ein Singleton zu erstellen ..." Diese erste Behauptung ist falsch. Dafür gibt es zwei Hauptgründe. 1) Die Anwendungsklasse bietet eine bessere lebenslange Garantie für einen Anwendungsentwickler. Es ist garantiert die Lebensdauer der Anwendung. Ein Singleton ist nicht AUSSCHLIESSLICH an die Lebensdauer der Anwendung gebunden (obwohl dies effektiv ist). Dies mag für einen durchschnittlichen Anwendungsentwickler kein Problem sein, aber ich würde behaupten, dass dies genau die Art von Vertrag ist, die die Android-API anbieten sollte, und es bietet auch dem Android-System viel mehr Flexibilität, indem die Lebensdauer der zugehörigen Anwendungen minimiert wird Daten. 2) Die Anwendungsklasse stellt dem Anwendungsentwickler einen einzelnen Instanzinhaber für den Status zur Verfügung. Das unterscheidet sich sehr von einem Singleton-Staatsinhaber. Eine Liste der Unterschiede finden Sie oben unter dem Link zur Singleton-Erklärung.

Dianne fährt fort: "... wahrscheinlich etwas, das Sie in Zukunft bereuen, wenn Sie feststellen, dass Ihr Anwendungsobjekt zu einem großen Durcheinander der unabhängigen Anwendungslogik wird." Dies ist sicherlich nicht falsch, aber dies ist kein Grund, Singleton der Anwendungsunterklasse vorzuziehen. Keines von Dianes Argumenten liefert einen Grund dafür, dass die Verwendung eines Singleton besser ist als eine Anwendungsunterklasse. Sie versucht lediglich festzustellen, dass die Verwendung eines Singleton nicht schlechter ist als eine Anwendungsunterklasse, was ich für falsch halte.

Sie fährt fort: "Und dies führt natürlicher dazu, wie Sie diese Dinge verwalten sollten - sie bei Bedarf zu initialisieren." Dies ignoriert die Tatsache, dass es keinen Grund gibt, warum Sie nicht bei Bedarf auch mit einer Anwendungsunterklasse initialisieren können. Auch hier gibt es keinen Unterschied.

Dianne endet mit "Das Framework selbst verfügt über Tonnen und Tonnen von Singletons für all die kleinen gemeinsam genutzten Daten, die es für die App verwaltet, wie z. B. Caches geladener Ressourcen, Pools von Objekten usw. Es funktioniert hervorragend." Ich behaupte nicht, dass die Verwendung von Singletons nicht gut funktioniert oder keine legitime Alternative darstellt. Ich argumentiere, dass Singletons keinen so starken Vertrag mit dem Android-System abschließen wie die Verwendung einer Anwendungsunterklasse, und dass die Verwendung von Singletons im Allgemeinen auf ein unflexibles Design hinweist, das nicht einfach zu ändern ist und später zu vielen Problemen führt. Meiner Meinung nach ist der starke Vertrag, den die Android-API für Entwickleranwendungen bietet, einer der attraktivsten und angenehmsten Aspekte der Programmierung mit Android und hat zu einer frühen Entwicklerakzeptanz geführt, die die Android-Plattform zu ihrem heutigen Erfolg geführt hat.

Dianne hat im Folgenden ebenfalls einen zusätzlichen Nachteil bei der Verwendung von Anwendungsunterklassen erwähnt, der möglicherweise dazu beiträgt oder das Schreiben von weniger Leistungscode erleichtert. Dies ist sehr richtig, und ich habe diese Antwort bearbeitet, um zu betonen, wie wichtig es ist, Perf hier zu berücksichtigen und den richtigen Ansatz zu wählen, wenn Sie Anwendungsunterklassen verwenden. Wie Dianne feststellt, ist es wichtig zu bedenken, dass Ihre Anwendungsklasse jedes Mal instanziiert wird, wenn Ihr Prozess geladen wird (kann mehrere Male gleichzeitig sein, wenn Ihre Anwendung in mehreren Prozessen ausgeführt wird!), Auch wenn der Prozess nur für eine Hintergrundsendung geladen wird Veranstaltung. Es ist daher wichtig, die Anwendungsklasse eher als Repository für Zeiger auf gemeinsam genutzte Komponenten Ihrer Anwendung zu verwenden, als als Ort für die Verarbeitung!

Ich überlasse Ihnen die folgende Liste der Nachteile von Singletons, die aus dem früheren StackExchange-Link gestohlen wurden:

  • Unfähigkeit, abstrakte oder Schnittstellenklassen zu verwenden;
  • Unfähigkeit zur Unterklasse;
  • Hohe Kopplung über die Anwendung (schwer zu modifizieren);
  • Schwer zu testen (kann in Unit-Tests nicht gefälscht / verspottet werden);
  • Im veränderlichen Zustand schwer zu parallelisieren (erfordert umfangreiche Verriegelung);

und füge mein eigenes hinzu:

  • Unklarer und nicht verwaltbarer lebenslanger Vertrag, der nicht für die Entwicklung von Android (oder den meisten anderen) geeignet ist;

93
Vielen Dank Soonil - diese Art von Antworten sind der Grund, warum ich Stack Overflow so liebe. GUT GEMACHT!
Johnny Lambada

5
Für alle, die sich fragen, wie "diese Klasse im Anwendungs-Tag in Ihrem Manifest angegeben werden soll", gibt es zum jetzigen Zeitpunkt zwei weitere Antworten auf diese Frage, die beschreiben, wie dies zu tun ist (verwenden Sie android: name), eine von ebuprofen und eine von ebuprofen von Mike Brown.
Tyler Collier

9
Bald ist Ihre Antwort richtig, aber können Sie feststellen, dass wir <application android: name = ". MyApp" ... /> in die Android Manifest-Datei aufnehmen sollten?
Anticafe

12
Lassen Sie mich noch einmal wiederholen, Sie sollten Application for Globals nicht verwenden. Es ist nutzlos, bietet keine Vorteile gegenüber Singletons und kann aktiv schädlich sein, z. B. die Leistung beim Starten Ihres Prozesses beeinträchtigen. Zum Zeitpunkt der Erstellung der Anwendung haben Sie keine Ahnung, wofür Ihr Prozess erstellt wird. Wenn Sie Singletons nach Bedarf träge initialisieren, müssen Sie nur die erforderlichen Arbeiten ausführen. Wenn Ihr Prozess beispielsweise gestartet wird, um eine Sendung über ein Hintergrundereignis zu verarbeiten, gibt es keinen Grund, den von Ihrer Benutzeroberfläche benötigten globalen Status zu initialisieren.
Hackbod

14
Lassen Sie uns hier auch ganz klar sein: Alle Ihre Argumente gegen Singletons sind absolut gültig, wenn wir über Situationen sprechen, in denen Sie tatsächlich zwischen einem Singleton und einem anderen Ansatz wählen, der kein globaler ist. Singletons sind Globals, mit allen Vorbehalten bezüglich Globals, die zutreffen. Jedoch Anwendung ist auch ein Singleton . Sie entgehen diesen Problemen nicht, indem Sie zur Unterklassenanwendung wechseln. Eine Anwendung ist genau die gleiche wie ein Singleton (aber schlimmer). Sie können sich nur selbst täuschen, dass Sie etwas saubereres tun. Aber du bist nicht.
Hackbod

153

Erstellen Sie diese Unterklasse

public class MyApp extends Application {
  String foo;
}

Fügen Sie in der Datei AndroidManifest.xml android: name hinzu

Beispiel

<application android:name=".MyApp" 
       android:icon="@drawable/icon" 
       android:label="@string/app_name">

1
Dank dafür. Ich habe mich gefragt, wie ich es im Manifest erklären soll
Jemand irgendwo

3
Damit es für mich funktioniert, musste ich das "." innerhalb von ".MyApp"
Jemand irgendwo

3
Deklarieren Sie es einfach nach der Hauptaktivität, sonst kann es möglicherweise nicht installiert / bereitgestellt werden
sami

11
Ich möchte nur sagen, das geht in das MAIN-Anwendungs-Tag, das bereits vorhanden ist ... dies ist kein zweites :) musste auf die harte Tour lernen.
Bwoogie

java.lang.IllegalAccessException: access to class is not allowed
Raptor

142

Die von Soonil vorgeschlagene Methode, einen Status für die Anwendung beizubehalten, ist gut, hat jedoch eine Schwachstelle: Es gibt Fälle, in denen das Betriebssystem den gesamten Anwendungsprozess abbricht. Hier ist die Dokumentation dazu - Prozesse und Lebenszyklen .

Stellen Sie sich einen Fall vor - Ihre App tritt in den Hintergrund, weil Sie jemand anruft (die Telefon-App steht jetzt im Vordergrund). In diesem Fall && kann das Betriebssystem unter bestimmten Bedingungen (überprüfen Sie den obigen Link auf mögliche Fehler) Ihren Anwendungsprozess, einschließlich der ApplicationUnterklasseninstanz, beenden. Infolgedessen geht der Zustand verloren. Wenn Sie später zur Anwendung zurückkehren, stellt das Betriebssystem seinen Aktivitätsstapel und seine ApplicationUnterklasseninstanz wieder her, das myStateFeld jedoch null.

AFAIK, die einzige Möglichkeit, die Sicherheit des Staates zu gewährleisten, besteht darin, eine Art von Persistenz des Staates zu verwenden, z. B. eine private für die Anwendungsdatei oder SharedPrefernces(schließlich eine private für die Anwendungsdatei im internen Dateisystem).


10
+1 für das Fortbestehen mit SharedPreferences; So habe ich es gesehen. Ich finde es seltsam, das Präferenzsystem für den gespeicherten Zustand zu missbrauchen, aber es funktioniert so gut, dass das Problem nur eine Frage der Terminologie wird.
Cheezmeister

1
Könnten Sie bitte den Code posten (oder einen Link zu einer Erklärung bereitstellen), wie SharedPreferences verwendet wird, um das von Arhimed beschriebene Problem zu lösen
Jemand irgendwo

2
Einstellungen, Datenbank, Dateiserialisierung usw. Jede Aktivität kann den Status beibehalten, wenn sie den onSaveInstanceState verwendet. Es hilft jedoch nicht, wenn der Benutzer die Aktivität beendet und sie aus dem Verlaufsstapel entfernt, das Schließen erzwingt oder das Gerät ausschaltet .
Darren Hinderer

1
Dieses Verhalten ist sehr ärgerlich - es wäre nicht so schlimm, wenn die onTerminate () -Methode Ihrer Anwendung aufgerufen würde, damit Sie elegant mit der Situation umgehen können.
Dean Wild

2
Dies ist meiner Meinung nach die richtige Antwort. Es ist ein Fehler, sich auf dieselbe Anwendungsinstanz zu verlassen, die für alle Aktivitäten vorhanden ist. Nach meiner Erfahrung ist es durchaus üblich, dass Android Ihren gesamten Prozess vollständig herunterfährt und neu erstellt, während Sie im Hintergrund sind. Hintergrundinformationen können nur das Starten einer Kameraabsicht, einer Browserabsicht oder das Empfangen eines Telefonanrufs bedeuten.
Jared Kells

26

Nur eine Notiz ..

hinzufügen:

android:name=".Globals"

oder wie auch immer Sie Ihre Unterklasse für das vorhandene <application> Tag benannt haben. Ich habe immer wieder versucht, <application>dem Manifest ein weiteres Tag hinzuzufügen , und habe eine Ausnahme erhalten.


Hallo Gimbl. Ich hatte das gleiche Problem. Ich hatte auch mein eigenes <application> -Tag und als ich versuchte, ein weiteres <application> -Tag hinzuzufügen, hatte ich das gleiche Problem wie Sie (Ausnahmemeldung). Aber ich habe getan, was Sie erwähnt haben, und es hat nicht funktioniert. Ich füge android: name = ". GlobalClass" zu meinem <application> -Tag hinzu, aber es funktioniert nicht. Können Sie vollständig erklären, wie Sie es gelöst haben?
Sonhja

3
Gutes <manifest> <application android: name = ". GlobalData"> </ application> </ manifest>. Schlechtes <manifest> <application> </ application> <application android: name = ". GlobalData"> </ application> </ manifest>
Gimbl

13

Ich konnte auch nicht finden, wie das Anwendungs-Tag angegeben werden soll, aber nach vielem Googeln wurde aus den Dokumenten der Manifestdatei ersichtlich: Verwenden Sie android: name zusätzlich zum Standardsymbol und der Bezeichnung in der Zeilengruppe der Anwendung.

android: name Der vollständig qualifizierte Name einer für die Anwendung implementierten Anwendungsunterklasse. Wenn der Anwendungsprozess gestartet wird, wird diese Klasse vor einer der Komponenten der Anwendung instanziiert.

Die Unterklasse ist optional. Die meisten Anwendungen benötigen keine. Wenn keine Unterklasse vorhanden ist, verwendet Android eine Instanz der Basisanwendungsklasse.


13

Was ist mit der Sicherstellung der Sammlung von nativem Speicher mit solchen globalen Strukturen?

Aktivitäten haben eine onPause/onDestroy()Methode, die als Zerstörung bezeichnet wird, aber die Anwendungsklasse hat keine Entsprechungen. Welcher Mechanismus wird empfohlen, um sicherzustellen, dass globale Strukturen (insbesondere solche, die Verweise auf nativen Speicher enthalten) ordnungsgemäß gesammelt werden, wenn die Anwendung entweder beendet oder der Taskstapel in den Hintergrund gestellt wird?


1
Die naheliegende Lösung besteht darin, die Closeable- Schnittstelle für Ihre Objekte zu implementieren, die für native Ressourcen verantwortlich sind, und sicherzustellen, dass diese durch eine Try-with-Resources-Anweisung oder etwas anderes verwaltet werden. Im schlimmsten Fall können Sie immer einen Objekt-Finalizer verwenden.
bald

5

Sie müssen lediglich einen Anwendungsnamen wie den folgenden definieren, der funktioniert:

<application
  android:name="ApplicationName" android:icon="@drawable/icon">
</application>

4

Wie oben erläutert, konnte das Betriebssystem die ANWENDUNG ohne Benachrichtigung beenden (es gibt kein onDestroy-Ereignis), sodass diese globalen Variablen nicht gespeichert werden können.

SharedPreferences könnte eine Lösung sein, AUSSER Sie haben COMPLEX STRUCTURED-Variablen (in meinem Fall hatte ich ein Integer-Array zum Speichern der IDs, die der Benutzer bereits verarbeitet hat). Das Problem mit den SharedPreferences besteht darin, dass es schwierig ist, diese Strukturen jedes Mal zu speichern und abzurufen, wenn die erforderlichen Werte benötigt werden.

In meinem Fall hatte ich einen Hintergrund-SERVICE, damit ich diese Variablen dorthin verschieben konnte. Da der Service das Ereignis onDestroy hat, konnte ich diese Werte einfach speichern.


Es wird nicht garantiert, dass onDestroy () auch für einen Dienst aufgerufen wird.
Lernen Sie OpenGL ES

Ja, dies kann jedoch nur in kritischen Situationen passieren.
Adorjan Princz

4

Wenn einige Variablen in SQLite gespeichert sind und Sie sie in den meisten Aktivitäten Ihrer App verwenden müssen. dann Anwendung vielleicht der beste Weg, um es zu erreichen. Fragen Sie die Variablen beim Start der Anwendung aus der Datenbank ab und speichern Sie sie in einem Feld. Dann können Sie diese Variablen in Ihren Aktivitäten verwenden.

Finden Sie also den richtigen Weg, und es gibt keinen besten Weg.


3

Sie können ein statisches Feld haben, um diese Art von Status zu speichern. Oder legen Sie es in das Ressourcen-Bundle und stellen Sie es von dort auf onCreate (Bundle savedInstanceState) wieder her. Stellen Sie einfach sicher, dass Sie den von der Android-App verwalteten Lebenszyklus vollständig verstehen (z. B. warum login () bei einer Änderung der Tastaturausrichtung aufgerufen wird).


2

Verwenden Sie kein anderes <application>Tag in der Manifestdatei. Nehmen Sie nur eine Änderung am vorhandenen <application>Tag vor und fügen Sie diese Zeile hinzu android:name=".ApplicationName", ApplicationNamein der der Name Ihrer Unterklasse (zum Speichern des globalen Tags ) angegeben ist, die Sie erstellen möchten .

Schließlich sollte Ihr EINZIGES <application> Tag in der Manifestdatei folgendermaßen aussehen:

<application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/Theme.AppCompat.NoActionBar"
        android:name=".ApplicationName"
        >

1

Sie können Intents, Sqlite oder Shared Preferences verwenden. Wenn es um den Medienspeicher geht, wie Dokumente, Fotos und Videos, können Sie stattdessen die neuen Dateien erstellen.


1

Sie können dies mit zwei Ansätzen tun:

  1. Anwendungsklasse verwenden
  2. Gemeinsame Einstellungen verwenden

  3. Anwendungsklasse verwenden

Beispiel:

class SessionManager extends Application{

  String sessionKey;

  setSessionKey(String key){
    this.sessionKey=key;
  }

  String getSessisonKey(){
    return this.sessionKey;
  }
}

Sie können die obige Klasse verwenden, um die Anmeldung in Ihrer MainActivity wie folgt zu implementieren. Code sieht ungefähr so ​​aus:

@override 
public void onCreate (Bundle savedInstanceState){
  // you will this key when first time login is successful.
  SessionManager session= (SessionManager)getApplicationContext();
  String key=getSessisonKey.getKey();
  //Use this key to identify whether session is alive or not.
}

Diese Methode funktioniert für die temporäre Speicherung. Sie wissen wirklich nicht, wann das Betriebssystem die Anwendung wegen des geringen Arbeitsspeichers beenden wird. Wenn sich Ihre Anwendung im Hintergrund befindet und der Benutzer durch eine andere Anwendung navigiert, für deren Ausführung mehr Speicher erforderlich ist, wird Ihre Anwendung beendet, da das Betriebssystem Vordergrundprozessen mehr Priorität einräumt als dem Hintergrund. Daher ist Ihr Anwendungsobjekt null, bevor sich der Benutzer abmeldet. Daher empfehle ich, die oben angegebene zweite Methode zu verwenden.

  1. Gemeinsame Einstellungen verwenden.

    String MYPREF="com.your.application.session"
    
    SharedPreferences pref= context.getSharedPreferences(MyPREF,MODE_PRIVATE);
    
    //Insert key as below:
    
    Editot editor= pref.edit();
    
    editor.putString("key","value");
    
    editor.commit();
    
    //Get key as below.
    
    SharedPreferences sharedPref = getActivity().getPreferences(Context.MODE_PRIVATE);
    
    String key= getResources().getString("key");

0

Das Aktivitätsergebnis wird zuvor beim Fortsetzen aufgerufen. Verschieben Sie also Ihre Anmeldeprüfung auf "Wiederaufnahme" und Ihre zweite Anmeldung kann blockiert werden, sobald die zweite Aktivität ein positives Ergebnis zurückgegeben hat. On Resume wird jedes Mal aufgerufen, sodass Sie sich keine Sorgen machen müssen, dass es nicht beim ersten Mal aufgerufen wird.


0

Der Ansatz der Unterklasse wurde auch vom BARACUS-Framework verwendet. Aus meiner Sicht sollte die Unterklasse Application mit den Lebenszyklen von Android arbeiten. Dies ist, was jeder Anwendungscontainer tut. Anstatt dann Globals zu haben, registriere ich Beans in diesem Kontext und lasse sie in jede Klasse injizieren, die durch den Kontext verwaltet werden kann. Jede injizierte Bean-Instanz ist tatsächlich ein Singleton.

Einzelheiten finden Sie in diesem Beispiel

Warum manuell arbeiten, wenn Sie so viel mehr haben können?


0
class GlobaleVariableDemo extends Application {

    private String myGlobalState;

    public String getGlobalState(){
     return myGlobalState;
    }
    public void setGlobalState(String s){
     myGlobalState = s;
    }
}

class Demo extends Activity {

@Override
public void onCreate(Bundle b){
    ...
    GlobaleVariableDemo appState = ((GlobaleVariableDemo)getApplicationContext());
    String state = appState.getGlobalState();
    ...
    }
}

0

Sie können eine Klasse erstellen, die die Klasse erweitert Application, Ihre Variable dann als Feld dieser Klasse deklarieren und eine Getter-Methode dafür bereitstellen.

public class MyApplication extends Application {
    private String str = "My String";

    synchronized public String getMyString {
        return str;
    }
}

Verwenden Sie dann Folgendes, um auf diese Variable in Ihrer Aktivität zuzugreifen:

MyApplication application = (MyApplication) getApplication();
String myVar = application.getMyString();
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.