2012-06-12 2 views
12

Täglich gibt es viele Fragen der folgenden type auf SO:Warum werden Getter beim Zugriff auf Variablen zwischen Aktivitäten nicht bevorzugt?

Wie erhalte ich eine Variable von einem anderen Activity?

Die Antworten empfehlen normalerweise, SharedPreferences oder Intent.putExtra() zu verwenden.

Für mich ist eine getter Methode, was eine Methode wäre, um auf eine Variable aus einer anderen Klasse zuzugreifen. Immerhin ist die Activity, die in Betracht gezogen wird, eine Klasse, und ihre Variablen sind Klassenmitglieder.

Warum werden Getter-Methoden keinen Ansätzen wie SharedPreferences oder Intent-Extras vorgezogen?

ich über einfache Situationen sprechen, die dieses eine Variable zwischen Aktivitäten, zum Beispiel erfordern Zugriff auf:

class OneClass extends Activity { 
    int a; 

    .. 
    // some changes to a 
    .. 
} 

Und dann in einer anderen Klasse (Activity):

class SomeOtherClass extends Activity { 
    .. 
    // trying to access a here 
    .. 
} 

Ist ein getter Methode ein richtiger Ansatz hier oder nicht?

Nochmal - ich spreche nicht über Szenarien, wo diese Dinge eigentlich der richtige Weg sind. SharedPreferences für die dauerhafte Speicherung von kleinen Datenmengen, extras wie die Dokumentation sagt: Dies kann verwendet werden, um erweiterte Informationen für die Komponente bereitzustellen. Zum Beispiel, wenn wir eine Aktion haben eine E-Mail-Nachricht zu senden, könnten wir auch zusätzliche Stücke von Daten hier ein Thema zu liefern, Körper usw.


Da einige der Antworten wahrscheinlich angegeben haben, dass es bestimmte Szenarien gibt, wie zum Beispiel keine Garantie, dass die anderen Activity am leben sind, ich denke, es gibt wahrscheinlichere und korrekte Gründe, warum Leute vorschlagen, für Absichten und gemeinsame Präferenzen zu gehen.

Antwort

12

Die Antwort auf Ihre Frage ist zweifach:

  • Für die Meta-Aspekt, der SO ohnehin auf Meta gehört, wollen viele neue Programmierer sehen Android, Anwendungen zu schreiben, und bei Java saugen.
  • Für die andere Frage, in der Regel mit einem Getter und Setter wird nicht funktionieren, weil Sie Objekte zwischen Aktivitäten auf einfache Weise übergeben können. Obwohl Sie dies technisch mit Parcelable tun können, wird dies nicht empfohlen, und der bessere Weg besteht darin, eine Absicht zu verwenden, um Daten zwischen Anwendungskomponenten zu übertragen.
  • Ein weiterer Punkt dieser Highlights ist, dass Android-Apps eine minimale Menge an Zustand in Komponenten behalten sollten. Ich denke, das war ein großer Erfolg von Android. Wenn Sie sich Apps dort anschauen, gibt es im Durchschnitt viel weniger globalen Status als typische Programme, die in Java geschrieben sind. Die Programme sind auch kleiner, was zu erwarten ist, aber die Tatsache, dass eine atomare Aktivität den Zustand eines einzelnen Bildschirms darstellen kann und die Tatsache, dass ein einzelner Bildschirm normalerweise nicht so viele Zustände in der gesamten App beibehalten wird, führt zu einer guten logischen Trennung zwischen App-Komponenten.
+0

Es ist nicht nur Sie, jemand wird alle Antworten abwerten. – Malcolm

+0

@KristopherMicinski danke für die Antwort, dass auch in einer schnellen Zeit, und das auch, wenn die Frage von Moderatoren und nach unten Wähler angegriffen wurde. Löscht viele Dinge für mich. Danke noch einmal. :-) –

5

Die einfache Antwort ist, weil der Activity Lebenszyklus von Android OS gesteuert wird. Aktivitäten sind anders als normale Klassen, die durch den Benutzercode instanziiert werden und garantiert verfügbar sind, bis sie nicht mehr referenziert werden.

4

Ich glaube, der Grund, dass Aktivitäten keine Getter und Setter haben, ist mit dem Lebenszyklus einer Aktivität verbunden. Sie sollten wirklich nicht garantieren, dass andere Aktivitäten am Leben sind, denn wenn sie nicht auf dem Bildschirm sind, kann das System sie jederzeit bereinigen.

Um jedoch Ihrem Muster zu folgen, erweitern Sie die Anwendung und verwenden Getter und Setter dafür. How to declare global variables in Android?

+1

Vielleicht, aber die Verwendung globaler Variablen ist eine schlechte (und uninformierte) Idee in Android im Allgemeinen, und Opfer Android-Stil für eine Präferenz von Java-Stil scheint ziemlich erfunden. –

+0

Oh, ich stimme zu. Sie lernen, dass Globals in einer Intro-Programmierklasse schlecht sind. Ich habe nur versucht ihm zu zeigen, wie man dieses Muster benutzt. In meiner Erfahrung, die Anwendung zu erweitern, landet normalerweise alles darin und es wird ziemlich schnell ziemlich unordentlich. Guter Kommentar. Vielen Dank. –

2

Sie haben recht, wenn es um die grundlegende Klassenstruktur geht. Wenn Sie jedoch den Aktivitätslebenszyklus und das Speichermanagement in Betracht ziehen, ist es nicht logisch, die gesamte Aktivität für den Zugriff auf kleine Datenmengen aufrechtzuerhalten.

2

Die Situation ist etwas komplizierter als Sie vorschlagen. Wenn Sie nur Klassen schreiben, die im Lebenszyklus einer Aktivität existieren, und Sie möchten, dass sie auf bestimmte Mitglieder der Aktivität zugreifen, können Sie Getter und typische Java-Paradigmen verwenden.

Das besagt, dass Android keinen natürlichen Mechanismus enthält, um auf die Instanz einer anderen Aktivität zuzugreifen. Dies ist wahrscheinlich sehr beabsichtigt. Aktivitäten sollen auf unterschiedliche Art und Weise funktionieren. Der engste Vergleich ist, dass jede Aktivität wie eine Seite auf einer Website sein soll (daher wäre es nicht sinnvoll, auf eine andere Instanz einer Seite zu verweisen).

2

Ich glaube nicht, dass dies irgendwie einzigartig für Android ist. Jedes relativ hochentwickelte Java-basierte Framework hat höhere 'Regeln' wie dieses.

  • Java's Swing oder AWT beschränken den Aufruf bestimmter Methoden bestimmter Threads.
  • Java ME funktioniert in dieser Hinsicht sehr wie Android.
  • In Java EE - vergessen Sie etwas über Servlets oder EJBs mit static Mitgliedern zu teilen. Sie sind vielleicht nicht einmal auf derselben Maschine.
  • Um Ihre Frage direkt zu beantworten: Sie können nicht einfach "frei" auf Objekte zugreifen, wie Sie es in einem einfachen Java-Programm tun, da einige Annahmen davon abhängen, dass diese Objekte gerade sind in der gleichen ClassLoader.

    2

    Dies würde perfekt funktionieren, wenn das Programm steuern könnte, wenn Aktivitäten erstellt und zerstört werden. Aber das Problem ist, dass sie vom Betriebssystem verwaltet werden.

    Sie können einen Verweis auf eine andere Aktivität speichern. Nur was passiert, wenn es zerstört oder neu erschaffen wird? Sie haben einen Verweis auf die Klasseninstanz, die länger relevant ist und keine zuverlässigen Mittel zur Erkennung dieses Falls enthält.

    Gemeinsame Präferenzen und Absichten werden in diesen Fällen verwendet, da sie zustandsunabhängig sind. Was auch immer mit einer Aktivität passiert, Präferenzen werden immer in dem Zustand verfügbar sein, in dem sie waren. Absicht ist auch ein Objekt, das für sich selbst existiert und nicht abgestanden wird.

    3

    Hauptsächlich, weil der ganze Prozess des Sendens einer Absicht nicht so einfach ist. Eine Absicht kann durch das System wandern, zwischen Prozessen usw. ... kurz gesagt, das von Ihnen erstellte Objekt ist nicht dasselbe Objekt, das am Ende empfangen wird (dies kann bewiesen werden, wenn versucht wird, eine Absichtsklasse zu erweitern, an eine andere Aktivität zu senden und versuchen Sie es am anderen Ende in Ihre erweiterte Klasse zurück zu werfen, es ist einfach nicht das gleiche Objekt).

    Jetzt hasse das ich auch wirklich, das ist, warum ich einige Basisklassen erstellt haben, die mich mit Absichten helfen arbeiten (ich nenne sie BundleWrappers), die so etwas wie dies funktionieren würde:

    Sie eine POJO mit Getter/Setter erstellen , füllen Sie das Objekt und verwenden Sie es wie Sie möchten,

    dann wenn die Zeit kommt nur Serialize in ein Bündel und deserialize es in das gleiche Objekt am anderen Ende.

    dann haben Sie das gleiche Objekt mit Getter und Setter in der anderen Aktivität.

    Der Hauptgrund Intents saugen ist, dass Sie einen Weg finden müssen, um alle Schlüssel für die Extras zu verfolgen, und die zusätzliche Implementierung für das Serialisieren des Bündels.

    immer noch selbst mit meiner Methode ist es nicht einfach, Intents zu verwenden, aber es ist das Beste, was ich bis jetzt in Bezug auf Leistung und Objektorganisation gefunden habe.

    public abstract class BundleWrapper implements Parcelable { 
    
        protected static final String KEY_PARCELABLE = "key_parcelable"; 
    
        public static final String TAG = BundleWrapper.class.getSimpleName(); 
    
        public BundleWrapper() { 
         super(); 
        } 
    
        abstract Parcelable getParcelable(); 
    
        public Bundle toBundle(){ 
         final Bundle bundle = new Bundle(); 
         Parcelable parcelable = getParcelable(); 
         if (parcelable != null) { 
          bundle.setClassLoader(parcelable.getClass().getClassLoader()); 
          bundle.putParcelable(KEY_PARCELABLE, parcelable); 
         } 
         return bundle; 
        } 
    
        public static Object fromBundle(final Intent intent) { 
         return fromBundle(intent.getExtras()); 
        } 
    
        public static Object fromBundle(final Bundle bundle) { 
         if (bundle != null && bundle.containsKey(KEY_PARCELABLE)) { 
          bundle.setClassLoader(BundleWrapper.class.getClassLoader()); 
          return bundle.getParcelable(KEY_PARCELABLE); 
         } 
         return null; 
        } 
    
    } 
    

    Hier ist meine Basisklasse, dafür verwenden Sie es einfach erweitern und Parcel (den verzögerten Teil des Prozesses :) implementieren:

    public class WebViewFragmentBundle extends BundleWrapper implements Parcelable { 
    
        public static final String TAG = WebViewFragmentBundle.class.getSimpleName(); 
    
        private String url; 
        public WebViewFragmentBundle() { 
         super(); 
        } 
    
        public WebViewFragmentBundle(Parcel source) { 
         this.url = source.readString(); 
        } 
    
        public String getUrl() { 
         return url; 
        } 
    
    
        public void setUrl(String url) { 
         this.url = url; 
        } 
    
        @Override 
        Parcelable getParcelable() { 
         return this; 
        } 
    
        @Override 
        public int describeContents() { 
         return 0; 
        } 
    
        @Override 
        public void writeToParcel(Parcel dest, int flags) { 
         dest.writeString(url); 
        } 
    
        public static final Parcelable.Creator<WebViewFragmentBundle> CREATOR = new Parcelable.Creator<WebViewFragmentBundle>() { 
         @Override 
         public WebViewFragmentBundle createFromParcel(Parcel source) { 
          return new WebViewFragmentBundle(source); 
         } 
    
         @Override 
         public WebViewFragmentBundle[] newArray(int size) { 
          return new WebViewFragmentBundle[size]; 
         } 
        }; 
    
    
    } 
    

    und für einen Anwendungsfall:

    public static void launchAugmentedRealityActivityForResult(final Activity context, WebViewFragmentBundle wrapper) { 
         final Intent intent = new Intent(context, Augmented.class); 
         intent.putExtras(wrapper.toBundle()); 
         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); 
         context.startActivityForResult(intent, AUGMENTED_RESULT_CODE); 
        } 
    

    und wirft es am anderen Ende wie:

    (WebViewFragmentBundle)BundleWrapper.fromBundle(getIntent()); 
    
    2

    Um Ihr Beispiel zu verwenden, ist das erste Problem, das Sie haben, einen Verweis auf eine Instanz von OneClass zu SomeOtherClass zu übergeben. SomeOtherClass würde einen Verweis auf die Instanz OneClass benötigen, um zu rufen. Es gibt keine einfache Möglichkeit, dies zu tun, denn wenn eine Aktivität eine andere Aktivität startet, ruft sie startActivity() auf und übergibt eine Absicht. Das ist der Mechanismus, den Sie bereit haben, um Parameter an eine Aktivität zu übergeben, wenn Sie sie starten, weshalb Sie sie wahrscheinlich verwenden sollten.

    Wenn Sie Ihrem Beispiel folgen, können Sie eine statische (Klassen-) Variable verwenden, um die Daten zwischen den Aktivitäten zu speichern. So könnte man so etwas tun:

    class OneClass extends Activity { 
        private static int a; 
    
        public static int getA() { 
         return a; 
        } 
    
        .. 
        // some changes to a 
        .. 
    } 
    
    class SomeOtherClass extends Activity { 
        .. 
        // trying to access a here 
        int myA = OneClass.getA(); 
    } 
    

    Dies setzt allerdings voraus ziemlich viel, dass es nur eine Instanz von OneClass sein wird, und das ist, wo es bricht alles IMHO. In Android werden überall Aktivitäten erstellt und zerstört. Es kann mehrere Instanzen einer Aktivität zu einem bestimmten Zeitpunkt geben und Sie wissen nie, wie viele Sie haben oder welche gerade aktiv ist. Das macht statische Variablen innerhalb von Aktivitätsklassen schwierig zu korrigieren. Zum Übergeben von Daten zwischen Aktivitäten würde ich die Extras in Intent verwenden, da es klar ist, dass Sie Daten übergeben, wenn Sie eine Aktivität starten. Es ist selbstdokumentierend.

    Auf der anderen Seite, wenn Sie Daten haben, die wirklich global für Ihre gesamte Anwendung sind, dann würde ich nur statische (Klasse) Variablen in einer Klasse verwenden, die direkt von allen Klassen zugänglich ist. Einige Leute Unterklasse Application, dies zu tun, aber die Dokumentation zeigt, dass Sie nicht müssen und im Allgemeinen müssen Sie nicht. Sie können nur so etwas tun:

    public class Globals { 
        public static int a; // Publicly available, don't need getter 
    } 
    

    Dann kann jede Klasse nur etwas speichern in Globals.a oder den Zugriff darauf. Sie müssen dazu keine Application ableiten.

    +0

    Danke für das Code-Snippet.Erklärt eine Menge. Upvoted es. Aber Entschuldigung kann es nicht akzeptieren. Danke noch einmal. :-) –

    0

    Lösung: Eine Aktivität ist eine Anwendungskomponente, sie hat ihren Lebenszyklus und Backstack im Gegensatz zu Klassen. Obwohl wir Objekte durch parcable und Serialisierung übergeben können, wird es jedoch nicht empfohlen. Wir können das Objekt durch ein Bündel im Intent-Objekt übergeben oder gemeinsame Präferenzen verwenden, um auf das Objekt zuzugreifen. Die Verwendung von Getter wäre keine gute Idee. Oder Sie können eine separate Constant Class erstellen und statisches Varable definieren und dann darauf zugreifen.

    Verwandte Themen