Dominar el contexto de Android

El contexto en Android es uno de los objetos más usados ​​y abusados. Pero la mayoría de los artículos de la web se centran en la definición de lo que es. No pude encontrar un buen recurso que me dio una idea y me ayudó a comprender el panorama general. Así que intenté simplificar las cosas con este artículo.

Prefacio

Mi misión para este artículo es ayudarte a dominar el contexto de Android. Este es uno de los temas centrales del desarrollo de Android, y casi ningún desarrollador usa el contexto por completo y de la forma en que fue diseñado.

Originalmente publiqué este artículo como una serie de cuatro publicaciones en mi sitio web. Si está interesado en leer capítulo por capítulo, no dude en leer allí.

Empezando

¿Alguna vez has encontrado con esta pregunta: ¿Cuál es la diferencia entre getContext(), this, getBaseContext()y getApplicationContext()? Si es así, este artículo ayudará a aclarar la mayor parte de su confusión.

Nota: debe conocer los conceptos básicos del desarrollo de Android, como Actividad, Fragmentos, Receptor de transmisión y otros componentes básicos. Si es un desarrollador nuevo que recién está comenzando su viaje hacia el mundo de Android, este podría no ser el mejor lugar para comenzar.

¿Qué diablos es el contexto?

Seamos realistas, el contexto es una de las características de la API de Android con peor diseño. Podría llamarlo el objeto "Dios".

Una aplicación de Android o un paquete de aplicaciones (APK) es un paquete de componentes. Estos componentes se definen en el Manifiesto y consisten principalmente en Actividad (UI), Servicio (Fondo), BroadcastReceiver (Acción), ContentProvider (Datos) y Recursos (imágenes, cadenas, etc.).

El desarrollador puede optar por exponer esos componentes a un sistema mediante un filtro de intención. Por ejemplo: envíe un correo electrónico o comparta una imagen. También pueden optar por exponer los componentes solo a otros componentes de su aplicación.

Del mismo modo, el sistema operativo Android también fue diseñado para exponer componentes. Algunos conocidos son WifiManager, Vibrator y PackageManager.

El contexto es el puente entre los componentes. Lo usa para comunicarse entre componentes, crear instancias de componentes y acceder a componentes.

Tus propios componentes

Usamos el contexto para crear instancias de nuestros componentes con Activity, Content Provider, BroadcastReceiver, etc. También lo usamos para acceder a recursos y sistemas de archivos.

Su componente y un componente del sistema

El contexto actúa como un punto de entrada al sistema Android. Algunos componentes del sistema más utilizados son WifiManager, Vibrator y PackageManager. Puede acceder a WifiManager usando context.getSystemService(Context.WIFI_SERVICE).

De la misma manera, puede usar el contexto para acceder al sistema de archivos dedicado a su aplicación como usuario en el sistema operativo.

Su propio componente y el componente de alguna otra aplicación

La comunicación entre sus propios componentes y los componentes de otras aplicaciones es casi idéntica si utiliza el enfoque de filtro de intención. Después de todo, todos los componentes son ciudadanos iguales en Android.

A continuación, se muestra un ejemplo de una intención utilizada para enviar correo electrónico. Todos los componentes que ofrecen esta acción de intención se entregarán al usuario, quien podrá optar por qué usar.

Intent emailIntent = new Intent(android.content.Intent.ACTION_SEND);

Resumen

Aceptemos que todo en Android es un componente. El contexto es el puente entre los componentes. Lo usa para comunicarse entre componentes, crear instancias de componentes y acceder a componentes. Espero que la definición esté clara ahora.

Diferentes tipos de contexto

Hay muchas formas de controlar el contexto ( mal diseño detectado ).

La mayoría de las veces usamos uno de los siguientes cuando necesitamos contexto:

- Application instance as context- Activity - Instance of your activity (this) - getApplicationContext() in Activity - getBaseContext() in Activity- Fragment - getContext() in Fragment- View - getContext() in View- Broadcast Receiver - Context received in broadcast receiver- Service - Instance of your service (this) - getApplicationContext() in Service- Context - getApplicationContext() in Context instance

Divido los tipos de contexto en dos categorías: contexto de IU y contexto sin IU . Esta distinción te ayudará a comprender n-waysun poco mejor.

Contexto de la interfaz de usuario

En realidad, solo ContextThemeWrapper es UI Context, lo que significa Context + Your theme .

La actividad se extiende ContextThemeWrapper. Esta es la razón por la que, cuando inflas cualquier XML, tus vistas tienen un tema. Si inflas tu diseño con un contexto sin interfaz de usuario, tu diseño no tendrá un tema. Adelante, pruébalo.

Cuando usa Activity como marcador de posición para el contexto, tiene la garantía de usar el contexto de la interfaz de usuario. Si usa el método getContext de Fragment, indirectamente está usando Activity (si adjuntó Fragment a través de fragmentManager en la actividad).

Pero view.getContext()no se garantiza que sea un contexto de interfaz de usuario.

Si se creó una instancia de View con Layout Inflater y se pasó el contexto de la interfaz de usuario, se recupera el contexto de la interfaz de usuario. Pero si se creó una instancia al no pasar el contexto de la interfaz de usuario, se recupera el otro contexto.

UI Context- Activity - Instance of your activity (this)- Fragment - getContext() in Fragment- View - getContext() in View (if View was constructed using UI-Context)

Contexto sin interfaz de usuario

Cualquier cosa, excepto el contexto de la interfaz de usuario, es un contexto que no es de interfaz de usuario. Técnicamente, todo lo que no sea ContextThemeWrapper es un contexto que no es de interfaz de usuario.

El contexto que no es de interfaz de usuario puede hacer casi todo lo que puede hacer el contexto de interfaz de usuario (se ha detectado un mal diseño ). Pero como señalamos anteriormente, pierde el tema.

Non-UI Context- Application instance as context- Activity - getApplicationContext() in Activity- Broadcast Receiver - Context received in broadcast receiver- Service - Instance of your service (this) - getApplicationContext() in Service- Context - getApplicationContext() in Context instance

Sugerencia : Se supone que todos los tipos de contexto son de corta duración, excepto el contexto de la aplicación. Este es el que obtiene de su clase de aplicación o al usar el getApplicationContext()método cuando tiene acceso al contexto.

Resumen

Lo hemos simplificado un poco poniendo Contexto en dos cubos. El contexto de la interfaz de usuario es Contexto + Tematización, y técnicamente cualquier clase que sea una subclase de ContextThemeWrapperviene en este segmento. El contexto que no es de interfaz de usuario son todos los demás tipos de contexto.

Dónde usar qué

The question arises: what will go wrong if you use context in the wrong place? Following are a few scenarios:

Scenario 1

Lets say you are inflating a layout and you use Non-UI Context. What may go wrong? You can guess in this case: you will not get a themed layout. Not so bad, hmm? It’s bearable.

Scenario 2

You pass UI-Context to someplace where all it needs is resource access or file system access. What can no wrong? Short Answer: Nothing. Remember, UI-Context = Context + Theme. It will gladly serve as context for you.

Scenario 3

You pass UI-Context to someplace where all it needs is resource access or file system access but it is a long operation in the background. Say downloading a file. Now what can go wrong? Short Answer: Memory leak.

If you are lucky and download completes quickly, the object is released and everything is fine. Sun is shining and birds are chirping. This is one of the most common mistakes developers make. They pass the reference of UI-Context to long living objects, and sometimes it has zero side effect.

However, sometimes Android wants to claim memory for either one of your next component’s requirements or another component’s requirements, and woooshhhh!!! You run out of memory in your app. Don’t worry, I will explain.

Memory Leak or Crash! That’s it.

Yes this is the worst case scenario when you use context in the wrong place. If you are new to the app development world, let me share some wisdom. Memory leaks are inversely proportional to your experience. Every Android developer has leaked memory. There is no shame in doing so.

Shame is when you repeat the mistake again and leak it the same way. If you leak memory a different way every time, congrats you are growing. I have explained what a Memory leak is with a short story here.

Okay I get it, but what is the relation of Context here?

Say it aloud, “Bad Design Spotted".

Almost everything in Android needs access to Context. Naive developers pass UI Context, because that’s what they have access to very easily. They pass short-living context (usually Activity context) to long living objects and before the memory/money is returned back to system, they hit a crisis. Woooshhh!!!

The simplest way to deal with this is with Async Task or Broadcast Receiver. But discussing them isn’t in the scope of this article.

Summary

  • Do you need to access UI related stuff? Use UI-Context. Inflating Views and showing dialogue are the two use cases I can think of.
  • Otherwise, Use Non UI Context.
  • Make sure you do not pass short-living context to long-living objects.
  • Pass knowledge, help people, plant trees and invite me for a coffee.

Tips and Tricks

What is the difference between this, getApplicationContext() and getBaseContext()?

This is one question every Android developer have encountered in their lives. I will try to simplify it as much as possible. Let’s take a step back and revisit the basics.

We know there are many factors in mobile devices. For instance, configuration changes all the time, and locale can change explicitly or implicitly.

All of these changes trigger apps to re-create so they can pick the right resources that are the best match to their current configuration. Portrait, Landscape, Tablet, Chinese, German, and so on. Your app needs the best possible resources to deliver the best user experience. It is the Context which is responsible for delivering those best match resources.

Try answering this question:

The user’s configuration is currently in portrait and you want to access landscape resources. Or the user locale is en and you want to access uk resources. How will you do it?

Below are some magical methods from Context:

There are many createX methods, but we are mainly interested in createConfigurationContext. Here is how you can use it:

Configuration configuration = getResources().getConfiguration();configuration.setLocale(your_custom_locale);context = createConfigurationContext(configuration);

You can get a hold of any type of Context you desire. When you call any method on the new Context you just got, you will get access to resources based on the configuration you had set.

I know it is amazing. You can send me thank you card.

Similarly, you can create a Themed Context and use it to inflate views with the theme you want.

ContextThemeWrapper ctw = new ContextThemeWrapper(this, R.style.YOUR_THEME);

Let’s come back to the tricky question we asked above and discuss Activity Context.

What is the difference between this, getApplicationContext()and getBaseContext()?

These are the possible ways you can get a hold on Context when you are in the Activity scope.

thispoints to Activity itself, our UI Context and short life context. getApplicationContext() points to your application instance which is Non-UI and long living context.

baseContext is the base of your Activity Context which you can set using a delegate pattern. You already know you can create Context with any xyz configuration you want. You can combine your xyz configuration knowledge with Base Context and your Activity will load resources as you desire.

Here is the method you can use:

@Overideprotected void attachBaseContext (Context base) {super.attachBaseContext(useYourCustomContext);}

Once BaseContext is attached, your Activity will delegate calls to this object. If you do not attach to Activity, it remains baseContext and you get Activity when you call getBaseContext.

Conclusion

We can say Context is the life of your android app. From Android’s point of view, it is your app. You can do almost nothing without Context. Without it, your app is plain Java code.

Context + Java code => Android

Good or bad, it is the design we have and we have to make the best of it. From the first part of this article, we learned that we use it to communicate between components, instantiate components, and access components.

In the next part, we learned that Context can be UI or NonUI, Short Lived or Long lived.

Following that, we learned that you need to choose context carefully otherwise you have to deal with memory leaks and other UI issues.

Finally, you saw that Context is responsible for loading best match resources for your app and you can configure it as you want. We also learned the difference between this, applicationContext and baseContext.

Many developers will advise you to use only application context. Do not use Application Context everywhere from the fear of a memory leak. Understand the root cause and always use the right Context in the right place.

You, my dear friend, are a master of Android Context now. You can suggest the next topic you want to understand. Click here to suggest.

Below are links from the original Series Mastering Android Contexton my blog.

Chapter 1

What the heck is Context? Why do we need it and what are various use cases in day to day development?

Chapter 2

Simplifying Context. We will discuss how many types of context are there and which ones are you suppose to use.

Chapter 3

Where to use UI Context and where to use Non UI-Context. How using context at wrong place may lead to memory leaks.

Chapter 4

My UI Context also offers me multiple types of context. Let’s answer this question and see how to avoid common pitfalls.

Training

Do you know that many times your app is crashing because your developers are not using Context properly? Let’s learn together. I offer training in Android, Java, and Git.

Want to master Android themes? Check out our series with more than 3k upvotes.

Feel free to share your feedback and questions. Happy Coding.

Follow me on Medium and Twitter for updates.