502 Stimmen

Anwendungskontext überall verwenden?

Ist bei einer Android-App etwas falsch an der folgenden Vorgehensweise?

public class MyApp extends android.app.Application {

    private static MyApp instance;

    public MyApp() {
        instance = this;
    }

    public static Context getContext() {
        return instance;
    }

}

und ihn überall dort übergeben (z.B. SQLiteOpenHelper), wo Kontext benötigt wird (und natürlich nicht durchsickert)?

23 Stimmen

Nur um dies für andere zu verdeutlichen, können Sie dann die <application> Knoten Ihrer AndroidManifest.xml-Datei, um die folgende Attributdefinition aufzunehmen: android:name="MyApp" . MyApp muss sich unter demselben Paket befinden, auf das Ihr Manifest verweist.

0 Stimmen

Warum die Statik? Die Anwendungsinstanz ist immer vor allen anderen geschaffen. Wo immer Sie auf den Anwendungskontext zugreifen sollen, wird er Ihnen als Argument übergeben. Dieser Ansatz kann Ihre Tests verkomplizieren. Static-itis fördert die allgemeine Kopplung.

6 Stimmen

AWESOME Weg, um das Problem der Bereitstellung eines Kontextes an den SQLiteOpenHelper zu umgehen! Ich habe ein Singleton "SQLiteManager" implementiert und war bei "wie zum Teufel bekomme ich einen Kontext zu dem Singleton?" stecken.

435voto

Reto Meier Punkte 95825

Es gibt einige potenzielle Probleme mit diesem Ansatz, obwohl er in vielen Fällen (wie in Ihrem Beispiel) gut funktioniert.

Besonders vorsichtig sollten Sie sein, wenn es um Dinge geht, die mit dem GUI die eine Context . Wenn Sie zum Beispiel den Anwendungskontext an die Funktion LayoutInflater erhalten Sie eine Exception. Im Allgemeinen ist Ihr Ansatz ausgezeichnet: Es ist gute Praxis, eine Activity's Context innerhalb dieser Activity und die Application Context bei der Übergabe eines Kontexts außerhalb des Bereichs einer Activity a Speicherlecks vermeiden .

Auch als alternativ zu Ihrem Muster können Sie die Abkürzung verwenden, indem Sie getApplicationContext() in einem Context Objekt (z. B. eine Aktivität), um den Anwendungskontext zu erhalten.

31voto

snctln Punkte 12105

Meiner Erfahrung nach sollte dieser Ansatz nicht notwendig sein. Wenn Sie den Kontext für irgendetwas brauchen, können Sie ihn normalerweise durch einen Aufruf von [Ansicht.getContext()](http://developer.android.com/reference/android/view/View.html#getContext()) und die Verwendung des Context dort erhalten, können Sie anrufen [Context.getApplicationContext()](http://developer.android.com/reference/android/content/Context.html#getApplicationContext()) um die Application Kontext. Wenn Sie versuchen, die Application Kontext dies aus einem Activity können Sie jederzeit anrufen [Aktivität.getAnwendung()](http://developer.android.com/reference/android/app/Activity.html#getApplication()) die als Context erforderlich für einen Aufruf an SQLiteOpenHelper() .

Insgesamt scheint es in dieser Situation kein Problem mit Ihrem Ansatz zu geben, aber wenn es um Context Vergewissern Sie sich nur, dass Sie nirgendwo Speicherplatz verlieren, wie es in der offiziellen Google Blog für Android-Entwickler .

14voto

18446744073709551615 Punkte 15274

Einige Leute haben gefragt: Wie kann das Singleton einen Null-Zeiger zurückgeben? Ich beantworte diese Frage. (Ich kann nicht in einem Kommentar antworten, weil ich den Code posten muss).

Zwischen zwei Ereignissen kann er null zurückgeben: (1) die Klasse wird geladen, und (2) das Objekt dieser Klasse wird erstellt. Hier ist ein Beispiel:

class X {
    static X xinstance;
    static Y yinstance = Y.yinstance;
    X() {xinstance=this;}
}
class Y {
    static X xinstance = X.xinstance;
    static Y yinstance;
    Y() {yinstance=this;}
}

public class A {
    public static void main(String[] p) {
    X x = new X();
    Y y = new Y();
    System.out.println("x:"+X.xinstance+" y:"+Y.yinstance);
    System.out.println("x:"+Y.xinstance+" y:"+X.yinstance);
    }
}

Führen wir den Code aus:

$ javac A.java 
$ java A
x:X@a63599 y:Y@9036e
x:null y:null

Die zweite Zeile zeigt, dass Y.xinstance y X.yInstanz son null ; sie sind null, weil die Variablen X.xinstance und Y.yInstanz wurden gelesen, wenn sie ungültig waren.

Kann dies behoben werden? Ja,

class X {
    static Y y = Y.getInstance();
    static X theinstance;
    static X getInstance() {if(theinstance==null) {theinstance = new X();} return theinstance;}
}
class Y {
    static X x = X.getInstance();
    static Y theinstance;
    static Y getInstance() {if(theinstance==null) {theinstance = new Y();} return theinstance;}
}

public class A {
    public static void main(String[] p) {
    System.out.println("x:"+X.getInstance()+" y:"+Y.getInstance());
    System.out.println("x:"+Y.x+" y:"+X.y);
    }
}

und dieser Code zeigt keine Anomalie:

$ javac A.java 
$ java A
x:X@1c059f6 y:Y@152506e
x:X@1c059f6 y:Y@152506e

BUT dies ist keine Option für Android Application Objekt: Der Programmierer hat keinen Einfluss auf den Zeitpunkt seiner Erstellung.

Noch einmal: Der Unterschied zwischen dem ersten und dem zweiten Beispiel ist, dass das zweite Beispiel eine Instanz erzeugt, wenn der statische Zeiger null ist. Aber ein Programmierer kann nicht erstellen die Android-Anwendungsobjekts, bevor sich das System dazu entschließt, dies zu tun.

UPDATE

Ein weiteres rätselhaftes Beispiel, bei dem initialisierte statische Felder zufällig null .

Main.java :

enum MyEnum {
    FIRST,SECOND;
    private static String prefix="<", suffix=">";
    String myName;
    MyEnum() {
        myName = makeMyName();
    }
    String makeMyName() {
        return prefix + name() + suffix;
    }
    String getMyName() {
        return myName;
    }
}
public class Main {
    public static void main(String args[]) {
        System.out.println("first: "+MyEnum.FIRST+" second: "+MyEnum.SECOND);
        System.out.println("first: "+MyEnum.FIRST.makeMyName()+" second: "+MyEnum.SECOND.makeMyName());
        System.out.println("first: "+MyEnum.FIRST.getMyName()+" second: "+MyEnum.SECOND.getMyName());
    }
}

Und Sie bekommen:

$ javac Main.java
$ java Main
first: FIRST second: SECOND
first: <FIRST> second: <SECOND>
first: nullFIRSTnull second: nullSECONDnull

Beachten Sie, dass Sie die Deklaration der statischen Variablen nicht eine Zeile nach oben verschieben können, da der Code sonst nicht kompiliert werden kann.

11voto

toha Punkte 4533

Anwendungsklasse:

import android.app.Application;
import android.content.Context;

public class MyApplication extends Application {

    private static Context mContext;

    public void onCreate() {
        super.onCreate();
        mContext = getApplicationContext();
    }

    public static Context getAppContext() {
        return mContext;
    }

}

Deklarieren Sie die Anwendung im AndroidManifest:

<application android:name=".MyApplication"
    ...
/>

Verwendung:

MyApplication.getAppContext()

9voto

Prasanta Punkte 277

Sie versuchen, einen Wrapper zu erstellen, um den Anwendungskontext abzurufen, und es besteht die Möglichkeit, dass er " null Zeiger".

Meines Erachtens ist es besser, eine der beiden Möglichkeiten zu wählen. Context.getApplicationContext() ou Activity.getApplication() .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X