Diferencia entre getContext(), getApplicationContext(), getBaseContext() y "esto"
¿Cuál es la diferencia entre getContext()
, getApplicationContext()
, getBaseContext()
y " this
"?
Aunque se trata de una pregunta sencilla, no puedo entender la diferencia básica entre ellas. Si es posible, proporcione algunos ejemplos sencillos.
View.getContext()
: Devuelve el contexto en el que se está ejecutando la vista actualmente. Generalmente, la actividad actualmente activa.Activity.getApplicationContext()
: Devuelve el contexto de toda la aplicación (el proceso en el que se ejecutan todas las actividades). Utilice esto en lugar del contexto de actividad actual si necesita un contexto vinculado al ciclo de vida de toda la aplicación, no solo a la actividad actual.ContextWrapper.getBaseContext()
: Si necesita acceder a un contexto desde otro contexto, utilice un ContextWrapper. Se accede al contexto al que se hace referencia desde el interior de ContextWrapper a través de getBaseContext().
La mayoría de las respuestas ya cubren getContext()
pero getBaseContext()getApplicationContext()
rara vez se explica.
El método getBaseContext()
sólo es relevante cuando tienes un archivo ContextWrapper
. Android proporciona una ContextWrapper
clase que se crea alrededor de una existente Context
usando:
ContextWrapper wrapper = new ContextWrapper(context);
El beneficio de usar a ContextWrapper
es que le permite "modificar el comportamiento sin cambiar el contexto original". Por ejemplo, si tiene una actividad llamada myActivity
, puede crear una View
con un tema diferente a myActivity
:
ContextWrapper customTheme = new ContextWrapper(myActivity) {
@Override
public Resources.Theme getTheme() {
return someTheme;
}
}
View myView = new MyView(customTheme);
ContextWrapper
es realmente poderoso porque le permite anular la mayoría de las funciones proporcionadas al Context
incluir código para acceder a recursos (p. ej. openFileInput()
, getString()
), interactuar con otros componentes (p. ej. sendBroadcast()
, registerReceiver()
), solicitar permisos (p. ej. checkCallingOrSelfPermission()
) y resolver ubicaciones del sistema de archivos (p. ej. getFilesDir()
). ContextWrapper
es realmente útil para solucionar problemas específicos del dispositivo/versión o para aplicar personalizaciones únicas a componentes como Vistas que requieren un contexto.
El método getBaseContext() se puede utilizar para acceder al contexto "base" que ContextWrapper
envuelve. Es posible que necesites acceder al contexto "base" si necesitas, por ejemplo, comprobar si es un Service
o :Activity
Application
public class CustomToast {
public void makeText(Context context, int resId, int duration) {
while (context instanceof ContextWrapper) {
context = context.baseContext();
}
if (context instanceof Service)) {
throw new RuntimeException("Cannot call this from a service");
}
...
}
}
O si necesita llamar a la versión "sin empaquetar" de un método:
class MyCustomWrapper extends ContextWrapper {
@Override
public Drawable getWallpaper() {
if (BuildInfo.DEBUG) {
return mDebugBackground;
} else {
return getBaseContext().getWallpaper();
}
}
}
La pregunta "¿qué es el contexto?" es una de las preguntas más difíciles en el universo de Android.
El contexto define métodos que acceden a los recursos del sistema, recuperan los activos estáticos de la aplicación, verifican los permisos, realizan manipulaciones de la interfaz de usuario y mucho más. En esencia, Context
es un ejemplo de antipatrón de Objeto Dios en producción.
Cuando se trata de qué tipo Context
deberíamos usar, se vuelve muy complicado porque, excepto por ser Objeto Dios, el árbol jerárquico de Context
subclases viola brutalmente el Principio de sustitución de Liskov.
Esta publicación de blog (ahora de Wayback Machine) intenta resumir Context
la aplicabilidad de las clases en diferentes situaciones.
Permítanme copiar la tabla principal de esa publicación para que esté completa:
+----------------------------+-------------+----------+---------+-----------------+-------------------+ | | Application | Activity | Service | ContentProvider | BroadcastReceiver | +----------------------------+-------------+----------+---------+-----------------+-------------------+ | Show a Dialog | NO | YES | NO | NO | NO | | Start an Activity | NO¹ | YES | NO¹ | NO¹ | NO¹ | | Layout Inflation | NO² | YES | NO² | NO² | NO² | | Start a Service | YES | YES | YES | YES | YES | | Bind to a Service | YES | YES | YES | YES | NO | | Send a Broadcast | YES | YES | YES | YES | YES | | Register BroadcastReceiver | YES | YES | YES | YES | NO³ | | Load Resource Values | YES | YES | YES | YES | YES | +----------------------------+-------------+----------+---------+-----------------+-------------------+
- Una aplicación PUEDE iniciar una Actividad desde aquí, pero requiere que se cree una nueva tarea. Esto puede adaptarse a casos de uso específicos, pero puede crear comportamientos de back stack no estándar en su aplicación y, en general, no se recomienda ni se considera una buena práctica.
- Esto es legal, pero la inflación se realizará con el tema predeterminado para el sistema que está ejecutando, no con el que está definido en su aplicación.
- Permitido si el receptor es nulo, que se utiliza para obtener el valor actual de una transmisión fija, en Android 4.2 y superior.
getApplicationContext() : devuelve el contexto de todas las actividades que se ejecutan en la aplicación.
getBaseContext() : si desea acceder al contexto desde otro contexto dentro de la aplicación, puede acceder.
getContext() : devuelve la vista de contexto solo la actividad en ejecución actual.