Verwenden der Android-Anwendungsklasse zum Speichern von Daten

112

Ich arbeite an einer ziemlich komplexen Android-Anwendung, die eine ziemlich große Datenmenge über die Anwendung benötigt (ich würde sagen, insgesamt etwa 500 KB - ist diese Größe für ein mobiles Gerät groß?). Soweit ich das beurteilen kann, führt jede Änderung der Ausrichtung in der Anwendung (genauer gesagt in der Aktivität) zu einer vollständigen Zerstörung und Wiederherstellung der Aktivität. Basierend auf meinen Erkenntnissen hat die Anwendungsklasse nicht den gleichen Lebenszyklus (dh sie wird in jeder Hinsicht immer instanziiert). Ist es sinnvoll, die Statusinformationen in der Anwendungsklasse zu speichern und dann aus der Aktivität heraus zu referenzieren, oder ist dies aufgrund von Speicherbeschränkungen auf Mobilgeräten im Allgemeinen nicht die "akzeptable" Methode? Ich freue mich über jeden Rat zu diesem Thema. Vielen Dank!

Dave
quelle
8
Denken Sie daran, dass Daten in Ihrer Anwendung weiterhin gelöscht werden können, wenn Ihre App in den Hintergrund tritt. Dies ist also keine Lösung für persistente Daten, die Sie immer wieder erhalten möchten. Es dient lediglich dazu, teure Objekte nicht so oft neu erstellen zu müssen.
Cheryl Simon
2
Mayra; Ich denke nicht, dass die App "normalerweise" gelöscht wird (obwohl, wie jemand später in diesem Thread betont, es "sein kann"). Ich werde wahrscheinlich einen "hybriden" Ansatz wählen, bei dem die Anwendung zum Speichern und Laden der Daten verwendet wird, aber dann das Attribut "android: Orientierung" für die Aktivität in der Manifestdatei verwenden, um das normale Verhalten von zu überschreiben Abriss und Wiederaufbau der Aktivität. All dies setzt natürlich voraus, dass die Anwendung bestimmen kann, wann sie zerstört wird, damit die Daten beibehalten werden können.
Dave

Antworten:

134

Ich denke nicht, dass 500 KB eine so große Sache sein werden.

Was Sie beschrieben haben, ist genau, wie ich mein Problem des Datenverlusts in einer Aktivität angegangen bin. Ich habe einen globalen Singleton in der Application-Klasse erstellt und konnte über die von mir verwendeten Aktivitäten darauf zugreifen.

Sie können Daten in einem globalen Singleton weitergeben, wenn sie häufig verwendet werden.

public class YourApplication extends Application 
{     
     public SomeDataClass data = new SomeDataClass();
}

Rufen Sie es dann in einer beliebigen Aktivität auf:

YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.

Ich diskutiere es hier in meinem Blog-Beitrag unter der Rubrik "Global Singleton".

Bryan Denny
quelle
1
Leider ist der betreffende Blog-Beitrag unter dieser Adresse nicht mehr verfügbar.
Mikebabcock
1
Ich habe Dinge auf meiner Website verschoben. Bis es behoben ist, finden Sie es auf archive.org hier: web.archive.org/web/20130818035631/http://www.bryandenny.com/…
Bryan Denny
1
Ich weiß, dass dies ein alter Beitrag ist, aber ich bin gerade auf ein Problem gestoßen, das dadurch gelöst werden könnte. Allerdings muss diese Klasse im Manifest irgendwie deklamiert werden, nicht wahr? Ich kann die Klasse nicht erreichen, also habe ich das Gefühl, dass mir das fehlt ...
Ziv Kesten
1
@ZivKesten Wie wäre es, wenn Sie dem Anwendungs-Tag im Manifest das Attribut name = hinzufügen?
MikeC
@mgc danke, es ist schon eine Weile her, und ja, so habe ich es schließlich herausgefunden. Außerdem habe ich Instanzen dieser Klasse erstellt, wo immer ich sie brauchte, indem ich ihr den getApplicationContext () mit einer Besetzung für diese Klasse gegeben habe
Ziv Kesten
57

Diejenigen, die auf ApplicationInstanz zählen, liegen falsch. Auf den ersten Blick mag es so aussehen, als ob das Applicationexistiert, solange der gesamte App-Prozess existiert, aber dies ist eine falsche Annahme.

Das Betriebssystem kann Prozesse nach Bedarf beenden. Alle Prozesse sind in 5 im Dokument angegebene "Killability" -Ebenen unterteilt .

Wenn Ihre App beispielsweise in den Hintergrund tritt, weil der Benutzer auf einen eingehenden Anruf antwortet, kann das Betriebssystem je nach RAM-Status Ihren Prozess beenden (oder auch nicht) (wodurch die ApplicationInstanz zerstört wird). .

Ich denke, ein besserer Ansatz wäre es, Ihre Daten in einer internen Speicherdatei zu speichern und sie dann zu lesen, wenn Ihre Aktivität wieder aufgenommen wird.

AKTUALISIEREN:

Ich habe viele negative Rückmeldungen erhalten, daher ist es an der Zeit, eine Klarstellung hinzuzufügen. :) Nun, anfangs habe ich wirklich eine falsche Annahme verwendet, dass der Status für die App wirklich wichtig ist. Wenn Ihre App jedoch in Ordnung ist, dass manchmal der Status verloren geht (es können einige Bilder sein, die nur erneut gelesen / heruntergeladen werden), ist es völlig in Ordnung, sie als Mitglied von beizubehalten Application.

Vit Khudenko
quelle
14
Wenn die Anwendung getötet wird, wen interessiert das dann? Die Anwendung ist weg. So wie ich es verstehe, wird Android Prozesse zurückfordern, die Speicher wie Aktivitäten enthalten. Wenn der Prozess, der die Anwendung enthält, abgebrochen wird (wenn Android das überhaupt tut?), Ist das im Wesentlichen wie das Beenden der App. Der Benutzer muss die App erneut starten und an diesem Punkt, wen interessiert das? Es ist eine neue Instanz der Anwendung.
Andrew
14
Dies war eine unangenehme Überraschung für uns in der Produktion. Glauben Sie mir, Android beendet Prozesse, es hängt nur vom RAM-Status und anderen in der Dokumentation beschriebenen Faktoren ab. Es war ein Albtraum für uns, also teile ich nur meine wirklichen Erfahrungen. Nun, wir hatten dies nicht auf Emulatoren, aber in der realen Welt sind einige Geräte mit Apps "überladen", so dass das Beenden eines Hintergrundprozesses eine normale Situation ist. Ja, wenn der Benutzer dann beschließt, die App in den Vordergrund zu stellen, stellt das Betriebssystem seinen Stapel einschließlich der ApplicationInstanz wieder her. Es gibt jedoch keine statischen Daten, auf die Sie zählen, es sei denn, Sie haben sie beibehalten.
Vit Khudenko
2
Ich denke, ich werde wahrscheinlich einen hybriden Ansatz verwenden. Ich wusste bereits über den offensichtlichen Trick Bescheid, um die Orientierungsänderung zu überschreiben (was andere Vorteile hat). Da es sich bei der Anwendung um ein Spiel handelt, bin ich mir nicht sicher, ob es "wichtig" genug ist, die Daten zwischen den Starts beizubehalten. obwohl es wahrscheinlich nicht besonders schwierig wäre, da die meisten Daten serialisiert werden können (obwohl ich nicht zwischen jeder Orientierungsänderung serialisieren und unserialisieren möchte). Ich schätze den Input auf jeden Fall. Ich würde nicht sagen, dass diejenigen, die von der App-Instanz abhängen, "falsch" sind. Viel hängt von der App ab :).
Dave
1
@Arhimed Sie verallgemeinern Ihre Antwort zu sehr. Und einen engen Ansatz vorschlagen, der auf Ihrer Annahme basiert. Falsche Annahme: Die in den statischen Variablen enthaltenen Daten müssen über die Sitzungen der App hinweg beibehalten werden. Es kann zahlreiche Anwendungsfälle geben, in denen die Daten trivial sind und nicht sofort beibehalten werden müssen.
Mandar Limaye
2
Ich habe ungefähr 1 MB Daten mit komplizierter Struktur. Das Serialisieren / Deserialisieren kann mich bis zu 2-3 Sekunden kosten, wenn das Gerät mit Arbeit überlastet ist. Die Idee, zwischen Aktivitäten zu sparen / zu laden, kostet zu viel Zeit. Ich benutze die Anwendung als Speicher. Natürlich muss meine in der Anwendungsinstanz gespeicherte Datenklasse jede Metod überprüfen - sind die Daten noch aktiv oder müssen geladen werden? Also muss Dave: 1. Lade- / Speicherfunktionen bereitstellen 2. Daten in der Anwendung aufbewahren. 3. Dreifache Überprüfungslogik für den Zugriff auf Daten.
Kostadin
6

Wenn Sie außerhalb einer Aktivität auf den "globalen Singleton" zugreifen möchten und nicht Contextalle beteiligten Objekte durchlaufen möchten, um den Singleton zu erhalten, können Sie einfach ein statisches Attribut in Ihrer Anwendungsklasse definieren, das den Verweis auf enthält selbst. Initialisieren Sie einfach das Attribut in der onCreate()Methode.

Beispielsweise:

public class ApplicationController extends Application {
    private static ApplicationController _appCtrl;

    public static ApplicationController getAppCtrl()
    {
         return _appCtrl;
    }
}

Da Unterklassen von Applicationauch die Ressourcen erhalten können, können Sie einfach darauf zugreifen, wenn Sie eine statische Methode definieren, die sie zurückgibt, wie z.

public static Resources getAppResources()
{
    return _appCtrl.getResources();
}

Seien Sie jedoch sehr vorsichtig, wenn Sie Kontextreferenzen weitergeben, um Speicherverluste zu vermeiden .

Saxos
quelle
6
Sie haben vergessen zu beachten, dass Sie android hinzufügen müssen: name = ". ApplicationController" xml-Attribut das Anwendungs-Tag in Ihrem Manifest, damit die Klasse instanziiert werden kann.
Eggie5
Sie müssen dazu nicht wirklich verlängern Application. Sie können dazu in jeder Klasse eine statische Elementvariable deklarieren .
David Wasser
2

Dave, um welche Art von Daten handelt es sich? Wenn es sich um allgemeine Daten handelt, die sich auf die gesamte Anwendung beziehen (Beispiel: Benutzerdaten), erweitern Sie die Anwendungsklasse und speichern Sie sie dort. Wenn sich die Daten auf die Aktivität beziehen, sollten Sie die Handler onSaveInstanceState und onRestoreInstanceState verwenden, um die Daten bei der Bildschirmdrehung beizubehalten.

Andrew
quelle
Was ist, wenn die Daten wirklich groß sind, um in einem Paket gespeichert zu werden? Dies ist, was ich bekomme: android.os.TransactionTooLargeException: Datenpaketgröße 838396 Bytes
Arjun Issar
1

Sie können die Orientierungsfunktion tatsächlich überschreiben, um sicherzustellen, dass Ihre Aktivität nicht zerstört und neu erstellt wird. Schau hier .

Grantland Chew
quelle
16
Sie können viele Dinge tun. Das heißt nicht, dass sie gute Ideen sind. Das ist keine gute Idee.
Andrew
Das Testen durch Ändern der Bildschirmausrichtung ist der einfachste Weg, um sicherzustellen, dass Ihre App das tut, was Android von ihr erwartet.
18446744073709551615
0

Sie können eine Anwendungsklasse erstellen und alle Daten auf diesem Calss speichern, um sie an einer beliebigen Stelle in Ihrer Anwendung zu verwenden.

Ashish Jaiswal
quelle
0

Ich weiß, dass dies die sehr alte Frage ist, aber die Verwendung des ViewModel aus den Jetpack-Komponenten ist der beste Weg, um die Daten zwischen Aktivitätsrotation zu erhalten.

Die ViewModel-Klasse dient zum lebenszyklusbewussten Speichern und Verwalten von UI-bezogenen Daten. Mit der ViewModel-Klasse können Daten Konfigurationsänderungen wie Bildschirmdrehungen überstehen.

Dharmendra
quelle