web-dev-qa-db-fra.com

Android Singleton avec contexte global

Selon la documentation Android, il indique:

Il n'est normalement pas nécessaire de sous-classer Application. Dans la plupart des situations, les singletons statiques peuvent fournir les mêmes fonctionnalités de manière plus modulaire. Si votre singleton a besoin d'un contexte global (par exemple pour enregistrer des récepteurs de diffusion), la fonction pour le récupérer peut se voir attribuer un contexte qui utilise en interne Context.getApplicationContext() lors de la première construction du singleton.

Comment puis-je créer un singleton statique qui a un contexte global pour qu'il survive à l'évolution de l'activité en cours dans mon application? Est-ce suffisant d'avoir un contexte statique qui référence la getApplicationContext ()?

43
Derek Gebhard

une autre modification de la question:

récemment (à partir de la majeure partie de 2016 et au-delà) ce que j'ai fait, et ce serait ma suggestion à tout développeur de le faire comme:

Utilisez Dagger2, utilisez simplement Dagger 2. Partout où vous avez besoin d'un Context vous faites:

@Inject Context context;

et c'est tout. Pendant que vous y êtes, injectez toutes les autres choses qui seraient un singleton.

réponse modifiée/améliorée:

parce que cette réponse devient un peu populaire, je vais améliorer ma propre réponse avec un exemple de code de ce que j'ai utilisé récemment (en juillet/2014).

Commencez par faire en sorte que l'application conserve une référence à elle-même.

public class App extends Application {
   private static App instance;
   public static App get() { return instance; }

   @Override
   public void onCreate() {
      super.onCreate();
      instance = this;
   }
}

puis sur tout singleton qui a besoin d'accéder au context je charge paresseusement les singles d'une manière sécurisée pour les threads en utilisant une synchronisation de double vérification comme expliqué ici https://stackoverflow.com/a/11165926/906362

private static SingletonDemo instance;

public static SingletonDemo get() {
   if(instance == null) instance = getSync();
   return instance;
}

private static synchronized SingletonDemo getSync() {
   if(instance == null) instance = new SingletonDemo();
   return instance;
}

private SingletonDemo(){
   // here you can directly access the Application context calling
   App.get();
}

réponse originale:

ce que la documentation suggère est d'utiliser un motif singleton normal

 public class SingletonDemo {
    private static SingletonDemo instance = null;

    private SingletonDemo() {       }

    public static SingletonDemo getInstance() {
            if (instance == null) {
                 instance = new SingletonDemo ();
            }
            return instance;
    }
}

et y inclure une méthode comme celle-ci:

 private Context context;
 init(Context context){
    this.context = context.getApplicationContext();
 }

et n'oubliez pas d'appeler cela pour initialiser le singleton.

La différence entre l'approche Application et l'approche Singleton et pourquoi le Singleton est meilleur réside dans la documentation same functionality in a more modular way

83
Budius

J'ai une telle classe dans ma candidature:

public class ApplicationContext {

    private Context appContext;

    private ApplicationContext(){}

    public void init(Context context){
        if(appContext == null){
            appContext = context;
        }
    }

    private Context getContext(){
        return appContext;
    }

    public static Context get(){
        return getInstance().getContext();
    }

    private static ApplicationContext instance;

    public static ApplicationContext getInstance(){
        return instance == null ?
                (instance = new ApplicationContext()):
                    instance;
    }
}

puis par exemple dans Launch Activity, initialisez-le:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //init
    ApplicationContext.getInstance().init(getApplicationContext());
    //use via ApplicationContext.get()
    assert(getApplicationContext() == ApplicationContext.get());
}
4
Mickey Tin