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.
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.
8 Stimmen
Nur damit Sie wissen, dass Sie Ihre Anwendung über eine ihrer Superschnittstellen zurückgeben. Wenn Sie also zusätzliche Methoden innerhalb von MyApp bereitstellen würden, könnten Sie diese nicht verwenden. Ihre getContext() sollte stattdessen einen Rückgabetyp von MyApp haben, und auf diese Weise können Sie später hinzugefügte Methoden sowie alle Methoden in ContextWrapper und Context verwenden.
5 Stimmen
Siehe auch goo.gl/uKcFn - es ist eine weitere Antwort auf einen ähnlichen Beitrag. Besser setzen Sie die statische Variable in onCreate und nicht c'tor.
0 Stimmen
Hat bei mir super funktioniert :) Thankx alex & Matt Hyuggins
0 Stimmen
Dies wird nicht funktionieren, wenn Ihr SQLiteOpenHelper von einem Content Provider verwendet wird, da das onCreate() des Content Providers vor dem onCreate() der Anwendung aufgerufen wird.
0 Stimmen
@MattHuggins Wenn mein Paketname com.example.xyz ist, kann ich ihn unter dem Anwendungsknoten wie folgt definieren: Android:name="com.example.xyz.MyApp" oder einfach Android:name="MyApp".
0 Stimmen
@yanchenko: Haben Sie das Szenario getestet, bei dem die GC Ihre Anwendung beendet? Würde Ihre Lösung dann noch funktionieren? Der Grund für meine Frage ist, dass es in Android Szenarien gibt, in denen eine Anwendung nach einem
Context
um bestimmte Aufgaben zu erledigen. Zum Beispiel das Abhören von Lautstärkeänderungen, die durch die Hardware-Lautstärketasten ausgelöst werden. Ich nehme an, dass in diesem Fall, wenn die App bereits von der GC beendet wurde, es keineContext
zur Verfügung steht, gibt es? Die einzige Lösung wäre dann, auf Null zu prüfenContext
und angemessen zu reagieren.1 Stimmen
@ChuongPham Wenn das Framework Ihre Anwendung beendet hat, gibt es nichts, was auf den Null-Kontext zugreift...
0 Stimmen
Ich glaube, Sie wollen anrufen
super()
von Ihrem Konstruktor.0 Stimmen
FWIW, für alle, die mit
Xamarin
Bei Android ist dies eingebaut alsglobal::Android.App.Application.Context
.