getApplication () vs. getApplicationContext ()

417

No pude encontrar una respuesta satisfactoria a esto, así que aquí vamos: ¿cuál es el trato Activity/Service.getApplication()y Context.getApplicationContext()?

En nuestra aplicación, ambos devuelven el mismo objeto. En una ActivityTestCasesin embargo, burlándose de la aplicación hará getApplication()volver con la maqueta, pero getApplicationContexttodavía devolver una instancia de contexto diferente (uno inyectado por Android). ¿Eso es un error? ¿Es a propósito?

Ni siquiera entiendo la diferencia en primer lugar. ¿Hay casos fuera de un conjunto de pruebas donde ambas llamadas pueden volver con diferentes objetos? ¿Cuándo y por qué? Además, ¿por qué se getApplicationdefine en Activityy Service, pero no en Context? ¿No debería haber siempre una instancia de aplicación válida disponible desde cualquier lugar ?

Matías
fuente
8
Buena pregunta. Las pruebas son un poco misteriosas (como bien sabes). Pero me pregunto si alguna diferencia se manifiesta en estas dos llamadas a métodos si no crea explícitamente un Applicationobjeto en su aplicación.
Christopher Orr

Respuestas:

366

Pregunta muy interesante Creo que es principalmente un significado semántico, y también puede deberse a razones históricas.

Aunque en las implementaciones actuales de Android Activity and Service, getApplication()y getApplicationContext()devuelve el mismo objeto, no hay garantía de que este sea siempre el caso (por ejemplo, en una implementación específica del proveedor).

Entonces, si desea la clase de Aplicación que registró en el Manifiesto, nunca debe llamarla getApplicationContext()y enviarla a su aplicación, porque puede que no sea la instancia de la aplicación (que obviamente experimentó con el marco de prueba).

¿Por qué getApplicationContext()existe en primer lugar?

getApplication()solo está disponible en la clase Actividad y la clase Servicio, mientras que getApplicationContext()se declara en la clase Contexto.

Eso realmente significa una cosa: cuando se escribe código en un receptor de difusión, que no es un contexto pero se le da un contexto en su método onReceive, solo puede llamar getApplicationContext(). Lo que también significa que no se garantiza que tenga acceso a su aplicación en un BroadcastReceiver.

Cuando mira el código de Android, ve que cuando se adjunta, una actividad recibe un contexto base y una aplicación, y esos son parámetros diferentes. getApplicationContext()delegados a los que está llamado baseContext.getApplicationContext().

Una cosa más: la documentación dice que en la mayoría de los casos, no debería necesitar subclasificar la aplicación:

Normalmente no hay necesidad de subclase Application. En la mayoría de las situaciones, los singletons 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), se le puede asignar a la función para recuperarlo una Contextque se usa internamente Context.getApplicationContext()cuando se construye el singleton por primera vez.

Sé que esta no es una respuesta exacta y precisa, pero aún así, ¿eso responde a su pregunta?

Pierre-Yves Ricau
fuente
89
@ Piwaï: No escuches el documento. Subclasificar android.app.Applicationes super ayuda completa. Por ejemplo, tuve un sinfín de problemas para inicializar la base de datos. Una vez que se mudó a Application.onCreateella funcionó como un encanto. Ahora hago toda la inicialización de todo el sistema Applicationy no escribiría otra aplicación sin ella.
Martin
99
@ Martin No escuchar los documentos generalmente significa que su código puede romperse en el futuro, o incluso ahora en condiciones inesperadas, perder portabilidad, tener un mal desempeño, evitar que los desarrolladores de la plataforma realicen un cambio beneficioso (eso rompe la suposición que hizo incorrectamente aunque fue basado solo en la implementación actual, no en los documentos). Creo que este es un comportamiento bastante malo y un consejo bastante malo.
Palec
17
@Palec: "Normalmente no hay necesidad de subclase Aplicación". - Eso es solo una pista. Todavía uso la funcionalidad oficialmente documentada de la manera prevista. - Solía ​​usar esos "singletons estáticos" al principio y resultaron ser un dolor en el ... - La inicialización perezosa tiene sus problemas. Especialmente cuando se usa con pruebas de instrumentación. - Todavía tengo esos Singletons para modularidad, pero los instancia en bloque en onCreate de una subclase de android.app.Application. - Funciona de maravilla.
Martin
99
@ Martin, debería haberlo dejado claro: mi reacción se refería solo a la primera oración. "No escuches al doctor". Este es generalmente un consejo muy peligroso. Pero "Esto es solo una pista: puedes ignorar el documento en este caso si tienes una razón y te mostraré una ..." me parece absolutamente bien.
Palec
3
"al escribir código en un receptor de difusión, que no es un contexto pero se le da un contexto en su método onReceive, solo puede llamar a getApplicationContext (). Lo que también significa que NO se garantiza que tenga acceso a su aplicación en un BroadcastReceiver. " Entonces, ¿qué podemos hacer para acceder a mi clase de aplicación en BroadcastReceiver?
Dr.jacky
30

Compara getApplication()y getApplicationContext().

getApplicationdevuelve un Applicationobjeto que le permitirá administrar el estado global de su aplicación y responder a algunas situaciones del dispositivo, como onLowMemory()y onConfigurationChanged().

getApplicationContextdevuelve el contexto de aplicación global: la diferencia con respecto a otros contextos es que, por ejemplo, un contexto de actividad puede ser destruido (o no estar disponible) por Android cuando finaliza su actividad. El contexto de la aplicación permanece disponible todo el tiempo que exista el objeto de la aplicación (que no está vinculado a un específico Activity), por lo que puede usarlo para cosas como las notificaciones que requieren un contexto que estará disponible por períodos más largos e independiente de los objetos de IU transitorios.

Supongo que depende de lo que esté haciendo su código si estos pueden o no ser los mismos, aunque en uso normal, esperaría que fueran diferentes.

RivieraKid
fuente
19
pero an Application es a Context(se hereda de él), y en tiempo de ejecución, ambos métodos devuelven la misma instancia. Entonces, ¿cuál es la diferencia?
Matthias
3
La diferencia es el alcance. El contexto de su Aplicación será válido por mucho más tiempo que, por ejemplo, un contexto de Actividad porque la actividad solo puede estar en uso por un tiempo muy corto, mientras que su Aplicación puede constar de muchas Actividades. Su contexto de actividad será válido durante al menos la duración que comienza cuando se inicia la primera actividad y finaliza cuando se realiza la última. Todos son contextos, pero uno es más duradero y no cambia, pero otros son de corta duración, y diferentes instancias pueden tener diferentes contextos.
RivieraKid
16
Creo que puedes estar leyendo mal mi pregunta. No estoy pidiendo la diferencia entre un Activitycontexto y un Applicationcontexto. Estoy reflexionando sobre la diferencia entre Application(que es el contexto de aplicación global único) y lo que sea que getApplicationContextregrese. Este último no era funcional antes de Android 1.6; solía volver siempre null.
Matthias
1
@Matthias En mi opinión, sigue siendo relevante. El propio sistema Android inyecta (implementa) el contexto, mientras que la Aplicación hereda y extiende el Contexto. La clase de aplicación se puede burlar fácilmente (como usted dijo), entonces, ¿no es una apuesta segura que muestra que la clase de aplicación hace algo de "magia" (en el proyecto de prueba) para lograrlo, posiblemente ignorando el contexto inyectado?
Audrius
3
¿Llegar de nuevo? Lo siento, todavía no veo cómo eso responde mi pregunta.
Matthias
30

Parece tener que ver con el ajuste de contexto. La mayoría de las clases derivadas Contextson en realidad a ContextWrapper, que esencialmente delega a otro contexto, posiblemente con cambios por el contenedor.

El contexto es una abstracción general que admite burlas y representación. Dado que muchos contextos están vinculados a un objeto de vida limitada, como un Activity, debe existir una forma de obtener un contexto de vida más larga, para fines tales como registrarse para futuras notificaciones. Eso se logra mediante Context.getApplicationContext(). Una implementación lógica es devolver el Applicationobjeto global , pero nada impide que una implementación de contexto devuelva un contenedor o proxy con una vida útil adecuada.

Las actividades y servicios están más específicamente asociados con un Applicationobjeto. La utilidad de esto, creo, es que se puede crear y registrar en el manifiesto de una clase personalizada derivada de Applicationy estar seguro de que Activity.getApplication()o Service.getApplication()va a devolver ese objeto específico de ese tipo específico, que puede convertir a su derivado de Applicationla clase y el uso por cualquier Propósito personalizado.

En otras palabras, getApplication()se garantiza que devolverá un Applicationobjeto, mientras que getApplicationContext()es libre de devolver un proxy en su lugar.

usethe4ce
fuente
Cuando dice "el contexto es una abstracción general que admite burlas y representación", ¿qué quiere decir exactamente con "representación"? ¿Podría señalarme algunas referencias? Todo el contexto me parece bastante complicado.
Tiago
@Tiago Esta respuesta puede ayudarlo a comprender mejor: stackoverflow.com/questions/10641144/…
superusuario
-13

Para responder la pregunta, getApplication () devuelve un objeto Application y getApplicationContext () devuelve un objeto Context. Basado en sus propias observaciones, supongo que el Contexto de ambos es idéntico (es decir, detrás de escena, la clase Aplicación llama a la última función para llenar la porción de Contexto de la clase base o se lleva a cabo alguna acción equivalente). Realmente no debería importar a qué función llame si solo necesita un Contexto.

Lenny Porter
fuente