¿Cuándo llamar al contexto de actividad O al contexto de la aplicación?

265

Ha habido muchas publicaciones sobre cuáles son estos dos contextos ... Pero todavía no lo estoy entendiendo bien

Según tengo entendido hasta ahora: cada uno es una instancia de su clase, lo que significa que algunos programadores recomiendan que lo use con la this.getApplicationContext()mayor frecuencia posible para no "perder" ninguna memoria. Esto se debe a que el otro this(obteniendo el Activitycontexto de la instancia) apunta a uno Activityque se está destruyendo cada vez que el usuario inclina el teléfono o sale de la aplicación, etc. ..

Pero, ¿puede alguien presentar algunos ejemplos de codificación realmente buenos en los que sería lo correcto usar this(obtener el contexto de la Activityinstancia actual ) y el contexto de la aplicación será inútil / incorrecto?

Norfeldt
fuente

Respuestas:

408

getApplicationContext()Casi siempre está mal. La Sra Hackborn (entre otros) han sido muy explícita que sólo se utiliza getApplicationContext()cuando se sabe por qué está utilizando getApplicationContext()y sólo cuando se necesita utilizar getApplicationContext().

Para ser franco, "algunos programadores" usan getApplicationContext()(o getBaseContext(), en menor medida) porque su experiencia en Java es limitada. Implementan una clase interna (por ejemplo, an OnClickListenerpara a Buttonen an Activity) y necesitan a Context. En lugar de usar MyActivity.thispara llegar a la clase externa ' this, usan getApplicationContext()o getBaseContext()para obtener un Contextobjeto.

Usted sólo se utiliza getApplicationContext()cuando se sabe que necesita un Contextalgo que puede vivir más tiempo que cualquier otro probable que Contextusted tiene a su disposición. Los escenarios incluyen:

  • Úselo getApplicationContext()si necesita algo vinculado a un elemento Contextque tenga alcance global. Yo uso getApplicationContext(), por ejemplo, en WakefulIntentService, para la estática WakeLockque se utilizará para el servicio. Como eso WakeLockes estático y necesito un Contextmétodo PowerManagerpara crearlo, es más seguro usarlo getApplicationContext().

  • Úselo getApplicationContext()cuando se une a a Servicedesde an Activity, si desea pasar el ServiceConnection(es decir, el identificador al enlace) entre Activityinstancias a través de onRetainNonConfigurationInstance(). Android realiza un seguimiento interno de los enlaces a través de estos ServiceConnectionsy contiene referencias a los Contextsque crean los enlaces. Si se vincula desde Activity, entonces la nueva Activityinstancia tendrá una referencia a la ServiceConnectionque tiene una referencia implícita a la anterior Activity, y la antigua Activityno se puede recolectar basura.

Algunos desarrolladores utilizan subclases personalizadas Applicationpara sus propios datos globales, que recuperan a través de getApplicationContext(). Eso es ciertamente posible. Prefiero miembros de datos estáticos, si no es por otra razón que solo puede tener unApplication objeto personalizado . Creé una aplicación usando un Applicationobjeto personalizado y me pareció doloroso. La Sra. Hackborn también está de acuerdo con esta posición .

Aquí hay razones por las que nogetApplicationContext() debes usar donde sea que vayas:

  • No es completo Context, apoya todo lo que Activityhace. Fallarán varias cosas que intentará hacer con esto Context, principalmente relacionadas con la GUI .

  • Puede crear pérdidas de memoria, si el Contextretenido getApplicationContext()retiene algo creado por sus llamadas que no limpia. Con un Activity, si se aferra a algo, una vez que Activityse recolecta la basura, todo lo demás también se elimina. El Applicationobjeto permanece durante toda la vida de su proceso.

CommonsWare
fuente
1
Muchas gracias por esta respuesta. Otro enlace que encontré antes de leer esta respuesta también podría ayudar a algunas personas. stackoverflow.com/questions/7298731/… - este enlace explica mis preocupaciones sobre la pérdida de memoria.
Norfeldt
27
@Norfeldt: Para su información, el enlace en su comentario enlaza con esta respuesta.
CommonsWare
2
gracias ... este fue el enlace: stackoverflow.com/questions/5796611/ ... describe la pérdida de memoria que tenía miedo de usar al usar esto
Norfeldt
66
@djaqeel: La última parte de su cita es casi cierta. Es mejor redactarlo como "no le dé un contexto de Actividad a algo que vivirá más tiempo que la Actividad, como un miembro de datos estático". Sin embargo, solo lo usa getApplicationContext()cuando sabe exactamente por qué lo necesita en una situación determinada. ¿Inflar un diseño? Usa la actividad. Enlace a un servicio, ¿dónde necesita ese enlace para sobrevivir a un cambio de configuración? Use getApplicationContext(), por lo que el enlace no está vinculado a la Activityinstancia.
CommonsWare
77
@Sever: cubro esto en mi respuesta. Dave Smith también tiene una excelente publicación de blog que cubre contextos: doubleencore.com/2013/06/context Su párrafo resumido: "En la mayoría de los casos, use el Contexto directamente disponible para usted desde el componente adjunto en el que está trabajando. una referencia a él siempre que esa referencia no se extienda más allá del ciclo de vida de ese componente. Tan pronto como necesite guardar una referencia a un Contexto de un objeto que viva más allá de su Actividad o Servicio, incluso temporalmente, cambie esa referencia que guarde al contexto de la aplicación ".
CommonsWare
48

Creo que hay muchas cosas que están mal documentadas en el sitio del SDK, esta es una de ellas. La afirmación que haré es que parece que es mejor usar el contexto de una aplicación por defecto y solo usar un contexto de actividad cuando realmente lo necesite. El único lugar donde he visto que necesitas un contexto de actividad es para un diálogo de progreso. SBERG412 afirma que tiene que usar un contexto de actividad para un mensaje brindis, sin embargo, los documentos de Android muestran claramente el contexto de una aplicación que se está utilizando. Siempre he usado el contexto de la aplicación para brindar por este ejemplo de Google. Si está mal hacerlo, Google dejó caer la pelota aquí.

Aquí hay más para pensar y revisar:

Para un mensaje de brindis, la Guía de desarrollo de Google usa el contexto de la aplicación y dice explícitamente que se use: Notificaciones de brindis

En la sección de diálogos de la guía de desarrollo, verá que un AlertDialog.Builder usa el contexto de la aplicación, y luego la barra de progreso usa un contexto de actividad. Google no lo explica. Cuadros de diálogo

Parece que una buena razón para usar el contexto de la aplicación es cuando desea manejar los cambios de configuración como un cambio de orientación, y desea retener objetos que necesitan un contexto como Vistas. Si mira aquí: Cambios en el tiempo de ejecución Hay una advertencia sobre el uso de un contexto de actividad, que puede crear una fuga. Esto se puede evitar con un contexto de aplicación con las vistas que se deben conservar (al menos eso entiendo). En una aplicación que estoy escribiendo, tengo la intención de usar un contexto de aplicación porque estoy tratando de mantener algunas vistas y otras cosas en un cambio de orientación, y todavía quiero que la actividad sea destruida y recreada en los cambios de orientación. Por lo tanto, tengo que usar un contexto de aplicación para no causar una pérdida de memoria (consulte Cómo evitar pérdidas de memoria) Para mí, parece que hay muchas buenas razones para usar el contexto de la aplicación en lugar de un contexto de actividad, y para mí casi parece que lo usarías con más frecuencia que un contexto de actividad. Eso es lo que parecen hacer muchos libros de Android por los que he pasado, y eso es lo que hacen muchos de los ejemplos de Google que he visto.

La documentación de Google realmente hace que parezca que usar el contexto de la aplicación está perfectamente bien en la mayoría de los casos, y de hecho aparece con más frecuencia que usar un contexto de actividad en sus ejemplos (al menos los ejemplos que he visto). Si realmente es un problema usar el contexto de la aplicación, entonces Google realmente necesita poner más énfasis en esto. Necesitan dejarlo en claro, y necesitan rehacer algunos de sus ejemplos. No atribuiría esto completamente a los desarrolladores inexpertos ya que la autoridad (Google) realmente hace que parezca que no es un problema usar contextos de aplicación.

Andi Jay
fuente
55
Estoy completamente de acuerdo. La respuesta de CommonsWare me sorprendió un poco. Me alegro de haber encontrado esta pregunta, porque la documentación de Google sugiere que usar getApplicationContext puede ser muy peligroso.
Steve Schwarcz
38

Utilicé esta tabla como guía sobre cuándo usar los diferentes tipos de contexto, como el contexto de la aplicación (es decir:) getApplicationContext()y el contexto de actividad , también el contexto de BroadcastReceiver :

ingrese la descripción de la imagen aquí

Todos los méritos van al autor original aquí para obtener más información.

CommonSenseCode
fuente
11

¿Qué contexto usar?

Hay dos tipos de contexto:

  1. El contexto de la aplicación está asociado con la aplicación y siempre será el mismo durante toda la vida de la aplicación; no cambia. Entonces, si está usando Toast, puede usar el contexto de la aplicación o incluso el contexto de la actividad (ambos) porque el toast se puede mostrar desde cualquier lugar de su aplicación y no está adjunto a una ventana específica. Pero hay muchas excepciones, una excepción es cuando necesita usar o pasar el contexto de actividad.

  2. El contexto de actividad está asociado a la actividad y puede destruirse si se destruye la actividad; puede haber múltiples actividades (más que probable) con una sola aplicación. Y a veces necesitas absolutamente el manejo del contexto de actividad. Por ejemplo, si inicia una nueva actividad, debe usar el contexto de actividad en su Intención para que la nueva actividad de inicio esté conectada a la actividad actual en términos de pila de actividades. Sin embargo, también puede usar el contexto de la aplicación para iniciar una nueva actividad, pero luego debe establecer el indicador Intent.FLAG_ACTIVITY_NEW_TASKcon la intención de tratarla como una nueva tarea.

Consideremos algunos casos:

  • MainActivity.this se refiere al contexto MainActivity que extiende la clase Activity pero la clase base (actividad) también extiende la clase Context, por lo que puede usarse para ofrecer el contexto de actividad.

  • getBaseContext() Ofrece contexto de actividad.

  • getApplication() Ofrece contexto de aplicación.

  • getApplicationContext() también ofrece contexto de aplicación.

Para obtener más información, consulte este enlace .

Zohra Khan
fuente
¿Qué pasa con el caso en que uno necesita mostrar un AlertDialog en la aplicación, por ejemplo, un proceso asíncrono que muestra un resultado? Un ejemplo de esto puede ser : el usuario hace clic en la descarga, inicia una solicitud de descarga downloadmanagery, cuando se recibe la señal finalizada, debe mostrar un cuadro de diálogo, por ejemplo, "¿Qué desea hacer con esta descarga?". Mi solución (piratear) guarda la más reciente Activityde una static Applicationclase y solicita la actual Activitycuando se completa la descarga. Sin embargo, dudo que esta sea la implementación adecuada. TL; DR ¿Cómo mostrar AlertDialog en cualquier lugar de la aplicación?
CybeX
@KGCybeX Si desea mostrar cualquier cosa y en cualquier lugar de su aplicación cuando se complete la descarga, debe registrar manualmente un receptor de transmisión en su actividad que escuche un mensaje específico que su servicio de descarga transmitirá y haga lo que quiera al recibir el mensaje, o adjunte su actividad a ese servicio directamente.
ExiRouS
6

Me preguntaba por qué no usar Contexto de aplicación para cada operación que admite. Al final, reduce la posibilidad de pérdida de memoria y falta de verificación nula para getContext () o getActivity () (cuando se utiliza el contexto de aplicación inyectada o se adquiere a través del método estático de Aplicación). Las declaraciones, como la de la Sra. Hackborn para usar el contexto de la aplicación solo si es necesario, no me parecen convincentes sin una explicación de por qué. Pero parece que he encontrado una falta de ropa por qué:

descubrimos que hay problemas en algunas combinaciones de versión / dispositivo de Android que no siguen estas reglas. Por ejemplo, si tengo un BroadcastReceiver que pasa un Contexto y convierto ese Contexto en un Contexto de Aplicación y luego trato de llamar a registerReceiver () en el Contexto de Aplicación, hay muchas instancias donde esto funciona bien, pero también muchas instancias donde obtengo un bloqueo debido a una ReceiverCallNotAllowedException. Estos bloqueos ocurren en una amplia gama de versiones de Android desde API 15 hasta 22. https://possiblemobile.com/2013/06/context/#comment-2443283153

¡Porque no está garantizado que todas las operaciones descritas como compatibles con el Contexto de aplicación en la tabla a continuación funcionen en todos los dispositivos Android! ingrese la descripción de la imagen aquí

Malaquiasz
fuente
4

Dos excelentes ejemplos de cuándo debe usar el contexto de actividad frente al contexto de la aplicación son cuando se muestra un mensaje Toast o un mensaje de diálogo incorporado, ya que el uso del contexto de la aplicación causará una excepción:

ProgressDialog.show(this, ....);

o

Toast t = Toast.makeText(this,....);

Ambos necesitan información del contexto Actividad que no se proporciona en el contexto Aplicación.

SBerg413
fuente
55
Hm .. ¿Qué versión del sistema operativo Android probaste? He probado en 4.4.4 y funciona bien. Además, como mencionó @Andi Jay, el documento oficial del desarrollador de Android utilizó el contexto de la aplicación en su código de muestra. developer.android.com/guide/topics/ui/notifiers/…
김준호
1
@ Nombre chino, sí, podría funcionar, pero en algún momento en el futuro de esa aplicación, también se bloqueará. Me sucedió varias veces.
Ojonugwa Jude Ochalifu
1
Cuando uso el contexto de actividad en Toast, ¡pierde memoria!
Jemshit Iskenderov
3

Contexto de aplicación en vivo hasta las que su aplicación está vivo única y es no depende de la actividad del ciclo de vida pero, el contexto objeto torreón de larga vida . Si el objeto que se usa temporalmente, ese tiempo, el Contexto de aplicación y el Contexto de actividad se usa totalmente opuesto al Contexto de aplicación.

Ganesh Katikar
fuente