¿Manera estática de obtener ‘Contexto’ en Android?

¿Hay alguna manera de obtener la instancia de Context actual dentro de un método estático?

Lo busco de esa manera porque odio guardar la instancia ‘Contexto’ cada vez que cambia.

Hacer esto:

En el archivo de Manifiesto de Android, declare lo siguiente.

   

Luego escribe la clase:

 public class MyApplication extends Application { private static Context context; public void onCreate() { super.onCreate(); MyApplication.context = getApplicationContext(); } public static Context getAppContext() { return MyApplication.context; } } 

Ahora, en todas partes, llame a MyApplication.getAppContext() para obtener el contexto de su aplicación estáticamente.

La mayoría de las aplicaciones que desean un método conveniente para obtener el contexto de la aplicación crean su propia clase que amplía la aplicación android.app.Application .

GUÍA

Puede lograr esto creando primero una clase en su proyecto como la siguiente:

 import android.app.Application; import android.content.Context; public class App extends Application { private static Application sApplication; public static Application getApplication() { return sApplication; } public static Context getContext() { return getApplication().getApplicationContext(); } @Override public void onCreate() { super.onCreate(); sApplication = this; } } 

Luego, en su AndroidManifest debe especificar el nombre de su clase en la etiqueta de AndroidManifest.xml:

  ...  

A continuación, puede recuperar el contexto de la aplicación en cualquier método estático usando lo siguiente:

 public static void someMethod() { Context context = App.getContext(); } 

ADVERTENCIA

Antes de agregar algo como lo anterior a su proyecto, debe considerar lo que dice la documentación:

Normalmente no hay necesidad de subclasificar la aplicación. En la mayoría de las situaciones, los singleton estáticos pueden proporcionar la misma funcionalidad de una manera más modular. Si su singleton necesita un contexto global (por ejemplo, para registrar receptores de difusión), la función para recuperarlo puede tener un Contexto que internamente utiliza Context.getApplicationContext () cuando construye el singleton por primera vez.


REFLEXIÓN

También hay otra forma de obtener el contexto de la aplicación usando la reflexión. La reflexión a menudo es despreciada en Android y personalmente creo que esto no debería usarse en producción.

Para recuperar el contexto de la aplicación debemos invocar un método en una clase oculta ( ActivityThread ) que ha estado disponible desde la API 1:

 public static Application getApplicationUsingReflection() throws Exception { return (Application) Class.forName("android.app.ActivityThread") .getMethod("currentApplication").invoke(null, (Object[]) null); } 

Hay una clase oculta más ( AppGlobals ) que proporciona una forma de obtener el contexto de la aplicación de una manera estática. Obtiene el contexto usando ActivityThread por lo que realmente no hay diferencia entre el siguiente método y el publicado anteriormente:

 public static Application getApplicationUsingReflection() throws Exception { return (Application) Class.forName("android.app.AppGlobals") .getMethod("getInitialApplication").invoke(null, (Object[]) null); } 

Feliz encoding!

No, no creo que exista. Lamentablemente, no puede getApplicationContext() desde Activity o alguna de las otras subclases de Context . Además, esta pregunta está relacionada de alguna manera.

Aquí hay una forma no documentada de obtener una Aplicación (que es un Contexto) desde cualquier lugar en el hilo de la interfaz de usuario. Se basa en el método estático oculto ActivityThread.currentApplication() . Debería funcionar al menos en Android 4.x.

 try { final Class activityThreadClass = Class.forName("android.app.ActivityThread"); final Method method = activityThreadClass.getMethod("currentApplication"); return (Application) method.invoke(null, (Object[]) null); } catch (final ClassNotFoundException e) { // handle exception } catch (final NoSuchMethodException e) { // handle exception } catch (final IllegalArgumentException e) { // handle exception } catch (final IllegalAccessException e) { // handle exception } catch (final InvocationTargetException e) { // handle exception } 

Tenga en cuenta que es posible que este método devuelva nulo, por ejemplo, cuando llama al método fuera del subproceso UI, o la aplicación no está vinculada a la cadena.

Todavía es mejor utilizar la solución de @RohitGhatol si puede cambiar el código de la Aplicación.

Suponiendo que estamos hablando de obtener el Contexto de la aplicación, lo implementé como lo sugiere la aplicación que extiende @Rohit Ghatol. Lo que sucedió entonces, es que no hay garantía de que el contexto recuperado de esa manera siempre sea no nulo. En el momento en que lo necesite, generalmente se debe a que desea inicializar un ayudante, u obtener un recurso, que no puede retrasarlo a tiempo; manejar el caso nulo no te ayudará. Así que entendí que básicamente estaba luchando contra la architecture de Android, como se indica en los documentos

Nota: normalmente no hay necesidad de subclasificar la aplicación. En la mayoría de las situaciones, los singleton estáticos pueden proporcionar la misma funcionalidad de una manera más modular. Si su singleton necesita un contexto global (por ejemplo, para registrar receptores de difusión), incluya Context.getApplicationContext () como argumento Context al invocar el método getInstance () de su singleton.

y explicado por Dianne Hackborn

La única razón por la que existe la Aplicación como algo de lo que se puede derivar es porque durante el desarrollo previo a la versión 1.0 uno de nuestros desarrolladores de aplicaciones me fastidiaba continuamente sobre la necesidad de tener un objeto de aplicación de alto nivel del que pudieran derivarse para tener una mayor “normalidad”. “para ellos modelo de aplicación, y finalmente cedí. Me arrepentiré por siempre de ceder en eso. 🙂

Ella también está sugiriendo la solución a este problema:

Si lo que quieres es un estado global que se pueda compartir en diferentes partes de tu aplicación, utiliza un singleton. […] Y esto conduce de manera más natural a cómo debe administrar estas cosas, inicializándolas a pedido.

así que lo que hice fue deshacerme de extender la Aplicación, y pasar el contexto directamente a getInstance () del ayudante singleton, mientras guardo una referencia al contexto de la aplicación en el constructor privado:

 private static MyHelper instance; private final Context mContext; private MyHelper(@NonNull Context context) { mContext = context.getApplicationContext(); } public static MyHelper getInstance(@NonNull Context context) { synchronized(MyHelper.class) { if (instance == null) { instance = new MyHelper(context); } return instance; } } 

la persona que llama luego pasará un contexto local al asistente:

 Helper.getInstance(myCtx).doSomething(); 

Por lo tanto, para responder a esta pregunta correctamente: hay formas de acceder al contexto de la aplicación estáticamente, pero todas deben ser desaconsejadas, y usted debería preferir pasar un contexto local al getInstance de singleton ().


Para cualquier persona interesada, puedes leer una versión más detallada en fwd blog

Depende de para qué estás usando el contexto. Puedo pensar al menos en una desventaja para ese método:

Si está intentando crear un AlertDialog con AlertDialog.Builder , el contexto de la Application no funcionará. Creo que necesitas el contexto para la Activity actual …

Si está abierto para usar RoboGuice , puede insertar el contexto en cualquier clase que desee. Aquí hay una pequeña muestra de cómo hacerlo con RoboGuice 2.0 (beta 4 al momento de escribir esto)

 import android.content.Context; import android.os.Build; import roboguice.inject.ContextSingleton; import javax.inject.Inject; @ContextSingleton public class DataManager { @Inject public DataManager(Context context) { Properties properties = new Properties(); properties.load(context.getResources().getAssets().open("data.properties")); } catch (IOException e) { } } } 

Lo he usado en algún momento:

 ActivityThread at = ActivityThread.systemMain(); Context context = at.getSystemContext(); 

Este es un contexto válido que utilicé para obtener servicios del sistema y funcionó.

Pero lo usé solo en modificaciones de framework / base y no lo intenté en aplicaciones de Android.

Una advertencia que debe saber: cuando se registre para receptores de difusión con este contexto, no funcionará y obtendrá:

java.lang.SecurityException: Dado que el paquete del llamador Android no se está ejecutando en el proceso ProcessRecord

Creo que necesitas un cuerpo para el método getAppContext() :

 public static Context getAppContext() return MyApplication.context; 

Puedes usar lo siguiente:

 MainActivity.this.getApplicationContext(); 

MainActivity.java:

 ... public class MainActivity ... { static MainActivity ma; ... public void onCreate(Bundle b) { super... ma=this; ... 

Cualquier otra clase:

 public ... public ANY_METHOD... { Context c = MainActivity.ma.getApplicationContext(); 

De acuerdo con esta fuente , puede obtener su propio Contexto extendiendo ContextWrapper

 public class SomeClass extends ContextWrapper { public SomeClass(Context base) { super(base); } public void someMethod() { // notice how I can use "this" for Context // this works because this class has it's own Context just like an Activity or Service startActivity(this, SomeRealActivity.class); //would require context too File cacheDir = getCacheDir(); } } 

JavaDoc para ContextWrapper

Proxying implementación de contexto que simplemente delega todas sus llamadas a otro contexto. Se puede subclasificar para modificar el comportamiento sin cambiar el contexto original.

Utilizo una variación del patrón de diseño de Singleton para ayudarme con esto.

 import android.app.Activity; import android.content.Context; public class ApplicationContextSingleton { private static Activity gContext; public static void setContext( Activity activity) { gContext = activity; } public static Activity getActivity() { return gContext; } public static Context getContext() { return gContext; } } 

Luego llamo a ApplicationContextSingleton.setContext( this ); en mi activity.onCreate () y ApplicationContextSingleton.setContext( null ); en onDestroy () ;

Acabo de lanzar un framework inspirado en jQuery para Android llamado Vapor API que tiene como objective simplificar el desarrollo de aplicaciones.

La clase $ fachada central mantiene un WeakReference (enlace a la increíble entrada del blog de Java sobre esto por Ethan Nicholas) al contexto de la Activity actual que puede recuperar llamando:

 $.act() 

Una WeakReference mantiene una referencia sin impedir que la recolección de basura recupere el objeto original, por lo que no debería tener problemas con las pérdidas de memoria.

La desventaja, por supuesto, es que corre el riesgo de que $.act() pueda devolver nulo. Sin embargo, aún no me he encontrado con este escenario, así que tal vez sea solo un riesgo mínimo, vale la pena mencionarlo.

También puede establecer el contexto manualmente si no está utilizando VaporActivity como su clase de Activity :

 $.act(Activity); 

Además, gran parte del marco API de Vapor utiliza este contexto almacenado de forma inherente, lo que puede significar que no es necesario que lo almacene en absoluto si decide utilizar el marco. Visite el sitio para obtener más información y ejemplos.

Espero que eso ayude 🙂

Si por alguna razón desea el contexto de la Aplicación en cualquier clase, no solo aquellos que extienden la aplicación / actividad, tal vez para algunas clases de fábrica o de ayuda. Puede agregar el siguiente singleton a su aplicación.

 public class GlobalAppContextSingleton { private static GlobalAppContextSingleton mInstance; private Context context; public static GlobalAppContextSingleton getInstance() { if (mInstance == null) mInstance = getSync(); return mInstance; } private static synchronized GlobalAppContextSingleton getSync() { if (mInstance == null) mInstance = new GlobalAppContextSingleton(); return mInstance; } public void initialize(Context context) { this.context = context; } public Context getApplicationContext() { return context; } } 

a continuación, inícielo en la clase de su aplicación onCreate con

 GlobalAppContextSingleton.getInstance().initialize(this); 

Úselo en cualquier lugar llamando

 GlobalAppContextSingleton.getInstance().getApplicationContext() 

Sin embargo, no recomiendo este enfoque para nada más que el contexto de la aplicación. Como puede causar pérdidas de memoria.

Así que modifiqué la respuesta aceptada porque está causando una pérdida de memoria, esto es lo que se me ocurrió …

AndroidManifest.xml

   ...  

MyApplication.java

 public class MyBakingAppContext extends Application { private static Object mContext; public void onCreate() { super.onCreate(); mContext = getApplicationContext(); } public static Context getAppContext() { return (Context)mContext; } } 

Lo que realmente hice fue asignar un contexto a un objeto y devolverlo como un contexto (fundiéndolo al contexto). Espero que ayude

Si no desea modificar el archivo de manifiesto, puede almacenar manualmente el contexto en una variable estática en su actividad inicial:

 public class App { private static Context context; public static void setContext(Context cntxt) { context = cntxt; } public static Context getContext() { return context; } } 

Y solo establece el contexto cuando comienza tu actividad (o actividades):

 // MainActivity @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Set Context App.setContext(getApplicationContext()); // Other stuff } 

Nota: como todas las otras respuestas, esta es una potencial pérdida de memoria.

Manera de Kotlin :

Manifiesto:

   

MyApplication.kt

 class MyApplication: Application() { override fun onCreate() { super.onCreate() instance = this } companion object { lateinit var instance: MyApplication private set } } 

A continuación, puede acceder a la propiedad a través de MyApplication.instance

He probado todas las sugerencias aquí descritas y puedo decir:

si uso el siguiente código:

 public class App extends Application { private static Context context; public void onCreate() { super.onCreate(); context = getApplicationContext(); } public static Context getAppContext() { return context; } } 

Entro en el Studio 3 un mensaje de error:

Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run) Do not place Android context classes in static fields; this is a memory leak (and also breaks Instant Run) .

Pero si uso el siguiente código:

 public class App extends Application { private static List context = new ArrayList<>(); @Override public void onCreate() { super.onCreate(); context.add(0, getApplicationContext()); } public static Context getAppContext() { return context.get(0); } } 

funciona bien sin ningún error.

La respuesta de Rohit parece correcta. Sin embargo, tenga en cuenta que la “Ejecución instantánea” de AndroidStudio depende de que no haya atributos de static Context en su código, hasta donde yo sé.