it-swarm.com.de

Wie können Daten zwischen Aktivitäten am besten ausgetauscht werden?

Ich habe eine Aktivität, bei der es sich um die Hauptaktivität handelt, die in der gesamten App verwendet wird, und es gibt eine Reihe von Variablen. Ich habe zwei weitere Aktivitäten, bei denen ich die Daten aus der ersten Aktivität verwenden möchte. Jetzt weiß ich, dass ich so etwas machen kann:

GlobalState gs = (GlobalState) getApplication();
String s = gs.getTestMe();

Ich möchte jedoch viele Variablen gemeinsam nutzen, und einige sind möglicherweise ziemlich groß, sodass ich keine Kopien davon wie oben erstellen möchte.

Gibt es eine Möglichkeit, die Variablen direkt abzurufen und zu ändern, ohne die Methoden get und set zu verwenden? Ich erinnere mich, dass ich in einem Artikel auf der Google-Entwickler-Website gelesen habe, dass dies für die Leistung unter Android nicht empfohlen wird.

230
Crazyfool

Hier eine Zusammenstellung von die gebräuchlichsten Methoden, um dies zu erreichen :

  • Daten in Absicht senden
  • Statische Felder
  • HashMap von WeakReferences
  • Objekte beibehalten (SQLite, Freigabeeinstellungen, Datei usw.)

TL; DR: Es gibt zwei Möglichkeiten, Daten auszutauschen: Übergeben von Daten in den Extras der Absicht oder Speichern an einem anderen Ort. Wenn es sich bei Daten um Primitive, Strings oder benutzerdefinierte Objekte handelt, senden Sie diese als Teil der Intent-Extras (benutzerdefinierte Objekte müssen Parcelable implementieren). Wenn komplexe Objekte übergeben werden, speichern Sie eine Instanz in einem Singleton an einer anderen Stelle und greifen Sie über die gestartete Aktivität auf sie zu.

Einige Beispiele, wie und warum jeder Ansatz implementiert werden sollte:

Senden Sie Daten in Absichten

Intent intent = new Intent(FirstActivity.this, SecondActivity.class);
intent.putExtra("some_key", value);
intent.putExtra("some_other_key", "a value");
startActivity(intent);

Bei der zweiten Aktivität:

Bundle bundle = getIntent().getExtras();
int value = bundle.getInt("some_key");
String value2 = bundle.getString("some_other_key");

Verwenden Sie diese Methode wenn Sie primitive Daten oder Strings übergeben. Sie können auch Objekte übergeben, die Serializable implementieren.

Obwohl verlockend, sollten Sie vor der Verwendung von Serializable zweimal überlegen: Es ist fehleranfällig und schrecklich langsam. Also im Allgemeinen: Finger weg von Serializable wenn möglich. Wenn Sie komplexe benutzerdefinierte Objekte übergeben möchten, werfen Sie einen Blick auf die Schnittstelle Parcelable. Es ist schwieriger zu implementieren, hat aber erhebliche Geschwindigkeitsgewinne im Vergleich zu Serializable.

Daten teilen, ohne auf der Festplatte zu bleiben

Es ist möglich, Daten zwischen Aktivitäten auszutauschen, indem Sie sie im Speicher speichern, da in den meisten Fällen beide Aktivitäten im selben Prozess ausgeführt werden.

Hinweis: Manchmal, wenn der Benutzer Ihre Aktivität verlässt (ohne sie zu beenden), kann sich Android) dazu entschließen, Ihre Anwendung zu beenden. In einem solchen Szenario habe ich Fälle erlebt in dem Android versucht, die letzte Aktivität mit der Absicht zu starten, die angegeben wurde, bevor die App beendet wurde. In diesem Fall werden Daten in einem Singleton (entweder Ihre oder Application) gespeichert Um solche Fälle zu vermeiden, müssen Sie entweder Objekte auf der Festplatte belassen oder die Daten überprüfen, bevor Sie sie verwenden, um sicherzustellen, dass sie gültig sind.

Verwenden Sie eine Singleton-Klasse

Haben Sie eine Klasse, um die Daten zu halten:

public class DataHolder {
  private String data;
  public String getData() {return data;}
  public void setData(String data) {this.data = data;}

  private static final DataHolder holder = new DataHolder();
  public static DataHolder getInstance() {return holder;}
}

Aus der gestarteten Aktivität:

String data = DataHolder.getInstance().getData();

Verwenden Sie den Anwendungs-Singleton

Der Anwendungs-Singleton ist eine Instanz von Android.app.Application, das beim Start der App erstellt wird. Sie können einen benutzerdefinierten Wert angeben, indem Sie Application erweitern:

import Android.app.Application;
public class MyApplication extends Application {
  private String data;
  public String getData() {return data;}
  public void setData(String data) {this.data = data;}
}

Vor dem Starten der Aktivität:

MyApplication app = (MyApplication) getApplicationContext();
app.setData(someData);

Dann aus der gestarteten Aktivität:

MyApplication app = (MyApplication) getApplicationContext();
String data = app.getData();

Statische Felder

Die Idee ist im Grunde die gleiche wie beim Singleton, aber in diesem Fall gewähren Sie statischen Zugriff auf die Daten:

public class DataHolder {
  private static String data;
  public static String getData() {return data;}
  public static String setData(String data) {DataHolder.data = data;}
}

Aus der gestarteten Aktivität:

String data = DataHolder.getData();

HashMap von WeakReferences

Dieselbe Idee, aber dem Garbage Collector erlauben, nicht referenzierte Objekte zu entfernen (z. B. wenn der Benutzer die Aktivität beendet):

public class DataHolder {
  Map<String, WeakReference<Object>> data = new HashMap<String, WeakReference<Object>>();

  void save(String id, Object object) {
    data.put(id, new WeakReference<Object>(object));
  }

  Object retrieve(String id) {
    WeakReference<Object> objectWeakReference = data.get(id);
    return objectWeakReference.get();
  }
}

Vor dem Starten der Aktivität:

DataHolder.getInstance().save(someId, someObject);

Aus der gestarteten Aktivität:

DataHolder.getInstance().retrieve(someId);

Möglicherweise müssen Sie die Objekt-ID mit den Extras der Absicht übergeben oder nicht. Es hängt alles von Ihrem spezifischen Problem ab.

Objekte auf der Festplatte beibehalten

Die Idee ist, die Daten auf der Festplatte zu speichern, bevor die andere Aktivität gestartet wird.

Vorteile: Sie können die Aktivität von anderen Orten aus starten. Wenn die Daten bereits vorhanden sind, sollte dies problemlos funktionieren.

Nachteile: Die Implementierung ist umständlich und dauert länger. Benötigt mehr Code und damit mehr Chancen, Fehler einzuführen. Es wird auch viel langsamer sein.

Einige der Möglichkeiten, Objekte beizubehalten, umfassen:

461
Cristian

Was können Sie verwenden:

  1. daten zwischen Aktivitäten austauschen (wie Cristian sagte)
  2. verwenden einer Klasse mit vielen statischen Variablen (sodass Sie sie ohne eine Instanz der Klasse und ohne Verwendung von Getter/Setter aufrufen können)
  3. Datenbank verwenden
  4. Gemeinsame Einstellungen

Was Sie wählen, hängt von Ihren Bedürfnissen ab. Wahrscheinlich werden Sie mehr als einen Weg verwenden, wenn Sie "viel" haben

22
WarrenFaith

Mach, was Google dir befiehlt! hier: http://developer.Android.com/resources/faq/framework.html#

  • Primitive Datentypen
  • Nicht persistente Objekte
  • Singleton-Klasse - mein Favorit: D
  • Ein öffentliches statisches Feld/eine Methode
  • Eine HashMap von WeakReferences zu Objekten
  • Persistente Objekte (Anwendungseinstellungen, Dateien, Inhaltsanbieter, SQLite DB)
16

"Wie auch immer, ich möchte eine Menge Variablen teilen und einige sind möglicherweise ziemlich groß, deshalb möchte ich keine Kopien davon wie oben erstellen."

Das macht keine Kopie (besonders mit String , aber selbst Objekte werden als Wert der Referenz übergeben, nicht das Objekt selbst, und Getter ist so sind gut zu gebrauchen - wohl besser zu gebrauchen als andere Mittel, weil sie verbreitet und gut verstanden sind). Die älteren "Performance-Mythen", zum Beispiel, dass keine Getter und Setter verwendet werden, haben immer noch einen gewissen Wert, aber wurden auch in den Dokumenten aktualisiert .

Wenn Sie dies nicht möchten, können Sie die Variablen auch einfach in GlobalState veröffentlichen oder als protected deklarieren und direkt darauf zugreifen. Und Sie können einen statischen Singleton erstellen, wie im Anwendungsobjekt, das JavaDoc angibt :

Normalerweise ist es nicht erforderlich, eine Unterklasse für die Anwendung festzulegen. In den meisten Fällen können statische Singletons die gleiche Funktionalität modularer bereitstellen. Wenn Ihr Singleton einen globalen Kontext benötigt (zum Beispiel zum Registrieren von Rundfunkempfängern), kann der Funktion zum Abrufen ein Kontext zugewiesen werden, der beim ersten Erstellen des Singleton intern Context.getApplicationContext () verwendet.

Die Verwendung von Intent-Daten ist eine weitere Möglichkeit, Daten weiterzuleiten. Sie wird jedoch normalerweise für kleinere Daten und einfache Typen verwendet. Sie können größere/komplexere Daten übergeben, dies ist jedoch aufwändiger als nur die Verwendung eines statischen Singleons. Das Application -Objekt ist immer noch mein persönlicher Favorit für den Austausch größerer/komplexerer nicht persistenter Daten zwischen Android - Anwendungskomponenten (da es in einer Android - App einen genau definierten Lebenszyklus aufweist). .

Wie andere angemerkt haben, können Sie auch SQLite oder das Dateisystem verwenden, wenn die Daten sehr komplex werden und persistent sein müssen .

14
Charlie Collins

Sie können die Application -Klasse und das Tag auf alle Objekte erweitern, die Sie dort haben möchten. Sie sind dann überall in Ihrer Anwendung verfügbar

7
Jimmy

Es gibt eine neue und bessere Möglichkeit, Daten zwischen Aktivitäten auszutauschen, und zwar LiveData . Beachten Sie insbesondere dieses Zitat von der Android Entwicklerseite:

Die Tatsache, dass LiveData-Objekte lebenszyklusabhängig sind, bedeutet, dass Sie sie für mehrere Aktivitäten, Fragmente und Dienste freigeben können. Um das Beispiel einfach zu halten, können Sie die LiveData-Klasse als Singleton implementieren

Dies hat eine enorme Auswirkung: Alle Modelldaten können in einer gemeinsamen Singleton-Klasse in einem Wrapper LiveData geteilt werden. Es kann aus Gründen der Testbarkeit aus den Aktivitäten in das jeweilige ViewModel injiziert werden. Und Sie müssen sich nicht mehr um schwache Referenzen sorgen, um Speicherverluste zu vermeiden.

2
Amir Uval

Es gibt verschiedene Möglichkeiten, Daten zwischen Aktivitäten auszutauschen

1: Übergeben von Daten zwischen Aktivitäten mit Intent

Intent intent=new Intent(this, desirableActivity.class);
intent.putExtra("KEY", "Value");
startActivity(intent)

2: Definieren Sie mit dem Schlüsselwort static die Variable als public static und verwenden Sie eine beliebige Stelle im Projekt

      public static int sInitialValue=0;

verwenden Sie classname.variableName an einer beliebigen Stelle im Projekt.

3: Datenbank verwenden

da der Vorgang jedoch etwas langwierig ist, müssen Sie die Abfrage zum Einfügen von Daten verwenden und Daten bei Bedarf mithilfe des Cursors iterieren. Es besteht jedoch keine Möglichkeit, Daten zu verlieren, ohne den Cache zu leeren.

4: Gemeinsame Einstellungen verwenden

viel einfacher als Datenbank. Es gibt jedoch eine Einschränkung, dass Sie ArrayList-, List- und Custome-Objekte nicht speichern können.

5: Erstellen Sie einen Getter-Setter in der Klasse Aplication und greifen Sie auf eine beliebige Stelle im Projekt zu.

      private String data;
      public String getData() {
          return data;
      }

      public void setData(String data) {
          this.data = data;
      }

hier einstellen und abholen von aktivitäten

         ((YourApplicationClass)getApplicationContext()).setData("abc"); 

         String data=((YourApplicationClass)getApplicationContext()).getData();  
2
vikas singh

Die Verwendung der oben und in http://developer.Android.com/guide/faq/framework.html beschriebenen Hashmap des schwachen Referenzansatzes scheint problematisch mir. Wie werden ganze Einträge zurückgefordert, nicht nur der Kartenwert? In welchem ​​Umfang ordnen Sie es zu? Da das Framework die Kontrolle über den Aktivitätslebenszyklus hat, kann es zu Laufzeitfehlern kommen, wenn einer der teilnehmenden Aktivitäten im Vorfeld seiner Clients zerstört wird. Wenn die Anwendung Eigentümer ist, muss eine Aktivität den Eintrag explizit entfernen, um zu verhindern, dass die Hashmap an Einträgen mit einem gültigen Schlüssel und einem möglicherweise fehlerhaft gesammelten schwachen Verweis festhält. Was sollte ein Client außerdem tun, wenn der für einen Schlüssel zurückgegebene Wert null ist?

Es scheint mir, dass eine WeakHashMap, die der Anwendung oder einem Singleton gehört, die bessere Wahl ist. Auf einen Wert in der Karte wird über ein Schlüsselobjekt zugegriffen, und wenn keine starken Verweise auf den Schlüssel vorhanden sind (d. H. Alle Aktivitäten werden mit dem Schlüssel und dessen Zuordnung durchgeführt), kann GC den Karteneintrag zurückfordern.

2
Mark Rosenberg

Daten zwischen Aktivitäten austauschen, beispielsweise eine E-Mail nach der Anmeldung

"email" ist der Name, mit dem auf den Wert der angeforderten Aktivität verwiesen werden kann

1 Code auf der Anmeldeseite

Intent openLoginActivity = new Intent(getBaseContext(), Home.class);
    openLoginActivity.putExtra("email", getEmail);

2 Code auf der Homepage

Bundle extras = getIntent().getExtras();
    accountEmail = extras.getString("email");
1
jeff

Nun, ich habe ein paar Ideen, aber ich weiß nicht, ob Sie danach suchen.

Sie können einen Dienst verwenden, der alle Daten enthält, und dann Ihre Aktivitäten zum Abrufen von Daten einfach an den Dienst binden.

Oder packen Sie Ihre Daten in ein serialisierbares oder parzellierbares Paket und hängen Sie sie an ein Bündel an und leiten Sie das Bündel zwischen Aktivitäten weiter.

Dieser ist möglicherweise überhaupt nicht das, wonach Sie suchen, aber Sie können auch versuchen, SharedPreferences oder eine Voreinstellung im Allgemeinen zu verwenden.

Wie auch immer, lassen Sie mich wissen, wie Sie sich entscheiden.

1
ahodder

Angenommen, Sie rufen Aktivität zwei von Aktivität eins mit einem Intent auf.
Sie können die Daten mit der intent.putExtra () übergeben,

Nehmen Sie dies als Referenz. Senden von Arrays mit Intent.putExtra

Hoffe das ist was du willst.

1
Manish Khot

Alle oben genannten Antworten sind großartig ... Ich füge nur eine hinzu, die noch niemand über das Speichern von Daten durch Aktivitäten erwähnt hat, und zwar mithilfe der integrierten SQLite-Datenbank Android, um relevante Daten zu speichern ... Tatsächlich können Sie Ihren databaseHelper in den Anwendungsstatus versetzen und ihn während der Aktivierungen nach Bedarf aufrufen. Oder Sie erstellen einfach eine Hilfsklasse und rufen die Datenbank bei Bedarf auf. Fügen Sie einfach eine weitere Ebene hinzu, die Sie berücksichtigen müssen von den anderen antworten würde auch genügen .. Wirklich nur präferenz

1
avatar

Wenn Sie beabsichtigen, andere Aktivitäten aus der aktuellen Aktivität aufzurufen, sollten Sie Absichten verwenden. Möglicherweise konzentrieren Sie sich weniger auf die Speicherung von Daten als auf die bedarfsgerechte Weitergabe.

Wenn Sie diese Werte jedoch wirklich beibehalten müssen, können Sie sie in einer strukturierten Textdatei oder Datenbank im lokalen Speicher beibehalten. In einer Eigenschaftendatei, XML-Datei oder JSON-Datei können Ihre Daten gespeichert und während der Aktivitätserstellung einfach analysiert werden. Vergessen Sie auch nicht, dass Sie SQLite auf allen Android) Geräten haben, sodass Sie sie in einer Datenbanktabelle speichern können. Sie können auch eine Map verwenden, um Schlüssel-Wert-Paare zu speichern und die Map zu serialisieren lokaler Speicher, aber dies kann zu umständlich sein, um für einfache Datenstrukturen nützlich zu sein.

1
Mike Yockey

Und wenn Sie mit Datenobjekten arbeiten möchten, sind diese beiden Implementierungen sehr wichtig:

Serializable vs Parcelable

  • Serializable ist eine Markierungsschnittstelle, die impliziert, dass der Benutzer die Daten nicht gemäß seinen Anforderungen marshallen kann. Wenn das Objekt "Serializable Java" implementiert, wird es automatisch serialisiert.
  • Parcelable ist Android eigenes Serialisierungsprotokoll. In Parcelable schreiben Entwickler benutzerdefinierten Code für das Marshalling und Unmarshalling. Dadurch werden im Vergleich zur Serialisierung weniger Müllobjekte erstellt
  • Die Leistung von Parcelable ist im Vergleich zu Serializable aufgrund seiner benutzerdefinierten Implementierung sehr hoch. Es wird dringend empfohlen, beim Serialisieren von Objekten in Android die Parcelable-Implantation zu verwenden.

public class User implements Parcelable

weitere Informationen finden Sie in hier

0
Diego Venâncio