Usando el contexto de la aplicación en todas partes?

En una aplicación de Android, ¿hay algún problema con el siguiente enfoque?

public class MyApp extends android.app.Application { private static MyApp instance; public MyApp() { instance = this; } public static Context getContext() { return instance; } } 

y pasarlo a todas partes (por ejemplo, SQLiteOpenHelper) donde se requiere contexto (y no fugas, por supuesto)?

Hay un par de problemas potenciales con este enfoque, aunque en muchas circunstancias (como su ejemplo) funcionará bien.

En particular, debe tener cuidado cuando se trata de algo que se relaciona con la GUI que requiere un Context . Por ejemplo, si pasa el Contexto de la aplicación al LayoutInflater , obtendrá una excepción. En general, su enfoque es excelente: es una buena práctica usar Activity's Context una Activity's dentro de esa Activity y el Application Context la Application Context al pasar un contexto más allá del scope de una Activity para evitar pérdidas de memoria .

Además, como alternativa a su patrón, puede usar el atajo de llamar a getApplicationContext() en un objeto Context (como una Actividad) para obtener el Contexto de la aplicación.

En mi experiencia, este enfoque no debería ser necesario. Si necesita el contexto para cualquier cosa, generalmente puede obtenerlo a través de una llamada a View.getContext () y usando el Contexto obtenido allí puede llamar a Context.getApplicationContext () para obtener el contexto de la Aplicación. Si intenta obtener el contexto de aplicación de una actividad, siempre puede llamar a Activity.getApplication (), que debería poder pasar como el contexto necesario para una llamada a SQLiteOpenHelper ()

En general, no parece que haya un problema con su enfoque para esta situación, pero cuando se trata de Contexto, asegúrese de no perder la memoria en ningún lado, como se describe en el blog oficial de Google Android Developers.

Algunas personas han preguntado: ¿cómo puede el singleton devolver un puntero nulo? Estoy respondiendo esa pregunta. (No puedo responder en un comentario porque necesito publicar el código).

Puede devolver nulo entre dos eventos: (1) la clase se carga y (2) se crea el objeto de esta clase. Aquí hay un ejemplo:

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

Vamos a ejecutar el código:

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

La segunda línea muestra que Y.xinstance y X.yinstance son nulos ; son nulos porque las variables X.xinstance ans Y.yinstance se leyeron cuando eran nulas.

¿Esto puede ser arreglado? Sí,

 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:"+Xy); } } 

y este código no muestra ninguna anomalía:

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

PERO esto no es una opción para el objeto Application Android: el progtwigdor no controla la hora en que se creó.

Una vez más: la diferencia entre el primer ejemplo y el segundo es que el segundo ejemplo crea una instancia si el puntero estático es nulo. Pero un progtwigdor no puede crear el objeto de la aplicación Android antes de que el sistema decida hacerlo.

Está intentando crear un contenedor para obtener el Contexto de la aplicación y existe la posibilidad de que pueda devolver el puntero ” null “.

Según mi entender, supongo que es un mejor enfoque para llamar a cualquiera de los 2 Context.getApplicationContext() o Activity.getApplication() .

Clase de aplicación:

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

Declare la aplicación en el AndroidManifest:

  

Uso:

 MyApplication.getAppContext() 

Es un buen enfoque. Lo uso yo también. Solo sugiero anular onCreate para establecer el singleton en lugar de usar un constructor.

Y desde que mencionó SQLiteOpenHelper : en onCreate () también puede abrir la base de datos.

Personalmente creo que la documentación se equivocó al decir que normalmente no hay necesidad de subclasificar la aplicación . Creo que es todo lo contrario: siempre debe subclasificar la aplicación.

Usaría Application Context para obtener un Servicio del sistema en el constructor. Esto facilita las pruebas y los beneficios de la composición

 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 clase de prueba usaría el constructor sobrecargado.

Android usaría el constructor predeterminado.

Me gusta, pero sugeriría un singleton en su lugar:

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

Estoy usando el mismo enfoque, sugiero escribir el singleton un poco mejor:

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

pero no lo estoy usando en todas partes, uso getContext() y getApplicationContext() donde puedo hacerlo!

Definir el contexto de forma estática causará la pérdida de memoria

Forma estándar de tener contexto en todas partes:

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

De esta manera, tendrás contexto en cualquier parte del código como este:

 App.contextReference.get(); 

Cualquier otra forma reducirá el rendimiento y causará la pérdida de memoria

Espero ser útil …