Pregunta ¿Manera estática de obtener 'Contexto' en Android?


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

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


812
2018-01-04 21:15


origen


Respuestas:


Hacer esto:

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

<application android:name="com.xyz.MyApplication">

</application>

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 todo el mundo llama MyApplication.getAppContext() para obtener su contexto de aplicación estáticamente.


1144
2018-02-25 06:37



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 se extiende 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:

<application 
    ...
    android:name="com.example.App" >
    ...
</application>

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 en un sistema más modular   camino. Si su singleton necesita un contexto global (por ejemplo para registrarse   receptores de difusión), la función para recuperarlo puede recibir una   Contexto que usa internamente Context.getApplicationContext () cuando   primero construyendo el singleton.


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 más oculta (AppGlobals) que proporciona una forma de obtener el contexto de la aplicación de una manera estática. Obtiene el contexto usando ActivityThread así 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 codificación!


59
2018-01-19 09:09



No, no creo que exista. Desafortunadamente, estás atrapado llamando getApplicationContext() de Activity o una de las otras subclases de Context. También, esta la pregunta está algo relacionada.


49
2018-01-05 00:46



Aquí hay un indocumentado forma de obtener un Solicitud (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, p. cuando llama al método fuera del subproceso UI, o la aplicación no está vinculada al subproceso.

Todavía es mejor usar @RohitGhatolsolución si puedes cambiar el código de la aplicación.


35
2017-09-19 13:34



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

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


31
2017-08-12 01:07



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 arquitectura de Android, como se indica en el 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 me rendí.   Me arrepentiré para 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, puede leer una versión más detallada en blog de fwd


28
2017-08-16 05:36



Si estás abierto a usar RoboGuice, puede tener el contexto inyectado 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) {
        }
    }
}

11
2018-02-29 14:46