Question

Dans une application Android, il n'y a rien de mal à l'approche suivante:

public class MyApp extends android.app.Application {

    private static MyApp instance;

    public MyApp() {
        instance = this;
    }

    public static Context getContext() {
        return instance;
    }

}

et passer partout (par exemple SQLiteOpenHelper) où le contexte est nécessaire (et ne fuit pas bien sûr)?

Était-ce utile?

La solution

Il y a quelques problèmes potentiels avec cette approche, bien que dans beaucoup de circonstances (comme votre exemple), il va bien travailler.

En particulier, vous devriez faire attention lorsqu'ils traitent avec tout ce qui traite de la GUI qui a besoin d'un Context . Par exemple, si vous passez le contexte de l'application dans le LayoutInflater vous obtiendrez une exception. D'une manière générale, votre approche est excellente: il est conseillé d'utiliser un lors du passage d'un contexte Activity's Context dans ce Activity et Application Context au-delà de la la portée d'une Activity éviter les fuites de mémoire .

En outre, comme autre à votre modèle, vous pouvez utiliser pour obtenir le contexte d'application le raccourci d'appeler getApplicationContext() sur une Context objet (comme une activité).

Autres conseils

Dans mon expérience cette approche ne devrait pas être nécessaire. Si vous avez besoin le contexte de tout ce que vous pouvez généralement obtenir via un appel à View.getContext () et en utilisant le Context obtenu là, vous pouvez appeler Context.getApplicationContext () pour obtenir le contexte Application. Si vous essayez d'obtenir le contexte de ce Application d'un Activity vous pouvez toujours appeler Activity.getApplication () qui devrait pouvoir être transmis en tant que Context nécessaire pour un appel à SQLiteOpenHelper().

Dans l'ensemble il ne semble pas être un problème avec votre approche de cette situation, mais lorsqu'il s'agit de Context assurez-vous de ne fuient pas la mémoire partout comme décrit sur le site officiel Google Android blog Développeurs .

Certaines personnes ont demandé: comment le singleton renvoie un pointeur NULL Je réponds à cette question. (Je ne peux pas répondre à un commentaire parce que je dois poster mon code.)

Il peut retourner null entre deux événements: (1) la classe est chargée, et (2) l'objet de cette classe est créée. Voici un exemple:

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);
    }
}

Lançons le code:

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

La deuxième ligne montre que Y.xinstance et X.yinstance sont null ; ils sont nuls parce que les variables X.xinstance ans Y.yinstance ont été lus quand ils étaient nuls.

Peut-on fixe? Oui,

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);
    }
}

et ce code ne montre aucune anomalie:

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

et ce n'est pas une option pour l'objet Application Android:. Le programmeur ne contrôle pas le moment où il est créé

Une fois de plus: la différence entre le premier exemple et le second est que le deuxième exemple crée une instance statique si le pointeur est nul. Mais un programmeur ne peut pas créer la objet application Android avant que le système décide de le faire.

UPDATE

Un autre exemple déroutante où les champs statiques initialisées arrivent à 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());
    }
}

Et vous obtenez:

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

Notez que vous ne pouvez pas déplacer la déclaration variable statique d'une ligne supérieure, le code ne compilera pas.

Vous essayez de créer un emballage pour obtenir contexte d'application et il y a une possibilité qu'il pourrait retourner un pointeur « de null ».

Selon ma compréhension, je suppose que sa meilleure approche Call- l'un des 2 Context.getApplicationContext() ou Activity.getApplication().

Classe d'application:

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;
    }

}

Déclarer l'application dans le AndroidManifest:

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

Utilisation:

MyApplication.getAppContext()

Il est une bonne approche. Je l'utilise moi-même. Je ne suggère de passer outre onCreate pour définir le singleton au lieu d'utiliser un constructeur.

Et comme vous l'avez mentionné SQLiteOpenHelper:. En onCreate () vous ouvrez la base de données ainsi

Personnellement, je pense que la documentation a tort de dire que Il n'y a normalement pas besoin de sous-classe d'application . Je pense que le contraire est vrai: Vous devez toujours sous-classe d'application

.

J'utiliser le contexte de l'application pour obtenir un service de système dans le constructeur. Cela facilite les tests et les avantages de la composition

public class MyActivity extends Activity {

    private final NotificationManager notificationManager;

    public MyActivity() {
       this(MyApp.getContext().getSystemService(NOTIFICATION_SERVICE));
    }

    public MyActivity(NotificationManager notificationManager) {
       this.notificationManager = notificationManager;
    }

    // onCreate etc

}

classe de test utilisera alors le constructeur surchargé.

Android utiliserait le constructeur par défaut.

Je l'aime, mais je suggère un singleton au lieu:

package com.mobidrone;

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

public class ApplicationContext extends Application
{
    private static ApplicationContext instance = null;

    private ApplicationContext()
    {
        instance = this;
    }

    public static Context getInstance()
    {
        if (null == instance)
        {
            instance = new ApplicationContext();
        }

        return instance;
    }
}

J'utilise la même approche, je vous suggère d'écrire singleton un peu mieux:

public static MyApp getInstance() {

    if (instance == null) {
        synchronized (MyApp.class) {
            if (instance == null) {
                instance = new MyApp ();
            }
        }
    }

    return instance;
}

mais je ne suis pas en utilisant partout, j'utilise getContext() et getApplicationContext() où je peux le faire!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top