Utiliser le contexte d’application partout?

Dans une application Android, y a-t-il quelque chose qui ne va pas dans 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 le passer partout (par exemple SQLiteOpenHelper) où le contexte est requirejs (et ne fuit pas bien sûr)?

Il y a quelques problèmes potentiels avec cette approche, mais dans de nombreuses circonstances (comme votre exemple), cela fonctionnera bien.

En particulier, vous devez faire attention lorsque vous traitez avec tout ce qui concerne l’ GUI nécessitant un Context . Par exemple, si vous transmettez l’application Context dans LayoutInflater vous obtiendrez une exception. En règle générale, votre approche est excellente: il est recommandé d’utiliser Activity's Context une Activity's dans cette Activity et le Application Context lors du passage d’un contexte au-delà de la scope d’une Activity pour éviter les memory leaks .

En outre, comme alternative à votre modèle, vous pouvez utiliser le raccourci d’appel de getApplicationContext() sur un object Context (tel qu’une activité) pour obtenir le contexte d’application.

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

Dans l’ensemble, il ne semble pas y avoir de problème avec votre approche pour cette situation, mais lorsque vous traitez avec le contexte, assurez-vous de ne pas laisser de mémoire nulle part comme décrit sur le blog officiel des développeurs Android de Google.

Certaines personnes ont demandé: comment le singleton peut-il retourner un pointeur nul? Je réponds à cette question. (Je ne peux pas répondre dans un commentaire parce que je dois poster du code.)

Il peut renvoyer null entre deux événements: (1) la classe est chargée et (2) l’object de cette classe est créé. 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(Ssortingng[] 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); } } 

Exécutons le code:

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

La deuxième ligne indique que Y.xinstance et X.yinstance sont null ; ils sont nuls car les variables X.xinstance et Y.yinstance ont été lues lorsqu’elles étaient nulles.

Est-ce que cela peut être corrigé? 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(Ssortingng[] p) { System.out.println("x:"+X.getInstance()+" y:"+Y.getInstance()); System.out.println("x:"+Y.x+" y:"+Xy); } } 

et ce code ne montre aucune anomalie:

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

MAIS ceci n’est pas une option pour l’object Application Android: le programmeur ne contrôle pas l’heure à laquelle il est créé.

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

Vous essayez de créer un wrapper pour obtenir le contexte d’application et il est possible qu’il renvoie un pointeur ” null “.

D’après ce que j’ai compris, je pense que sa meilleure approche consiste à appeler 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éclarez l’application dans AndroidManifest:

  

Usage:

 MyApplication.getAppContext() 

C’est une bonne approche. Je l’utilise moi aussi. Je suggérerais seulement de remplacer onCreate pour définir le singleton au lieu d’utiliser un constructeur.

Et comme vous avez mentionné SQLiteOpenHelper : Dans onCreate () vous pouvez également ouvrir la firebase database.

Personnellement, je pense que la documentation a eu tort de dire qu’il n’y a normalement pas besoin de sous-classe Application . Je pense que le contraire est vrai: vous devez toujours sous-classe Application.

J’utiliserais le contexte d’application pour obtenir un service 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 } 

La classe de test utiliserait alors le constructeur surchargé.

Android utiliserait le constructeur par défaut.

Je l’aime bien, mais je suggère plutôt un singleton:

 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 suggère d’écrire un peu mieux le singleton:

 public static MyApp getInstance() { if (instance == null) { synchronized (MyApp.class) { if (instance == null) { instance = new MyApp (); } } } return instance; } 

mais je n’utilise pas partout, j’utilise getContext() et getApplicationContext() où je peux le faire!

La définition statique du contexte provoquera la fuite de mémoire

Méthode standard pour obtenir un contexte partout:

 public class App extends Application { public static transient SoftReference contextReference; @Override public void onCreate() { super.onCreate(); contextReference = new SoftReference(getApplicationContext()); } } 

De cette façon, vous aurez un contexte n’importe où dans le code comme ceci:

 App.contextReference.get(); 

Toute autre manière réduira les performances et provoquera la fuite de mémoire

J’espère être utile …