Context en Android
Tags: android, mobile, kotlin
Published: 2023-04-13 17:59:04


![Context en Android infografia resumen](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tuipxe1qv7pxc04pyvjf.png)

---

## Indice
 * [Definición](#definición)
 * [Como obtener el context](#como-obtener-el-context)
 * [Uso](#usos)
   * [Iniciar Activity](#iniciar-activity)
   * [Inicir Servicios](#iniciar-servicios)
 * [Utilizarlo en Composables](#utilizarlo-en-composables)
 * [Utilizarlo en ViewModels](#utilizarlo-en-viewmodels)
 * [Referencias](#referencias)

---


## Definición 

Es una clase abstracta que la implementa Android, y cuya función es proporcionar acceso al entorno de la aplicación.

> Así se define en la documentación oficial pero en mi caso no entiendo a que se refiere.

Si tenemos acceso al entorno de la aplicación, vamos a tener acceso a las siguientes funciones:

1. Acceder a una base de datos
2. Al sistema de notificaciones
3. Al sistema de ficheros
4. Lanzar actividades, servicios
5. Trabajar con permisos
6. Mostrar cuadros de diálogo

----

## Como obtener el Context

La obtención del Context se puede realizar desde varios puntos en una app:

- Desde cualquier `Activity` 
- Desde un `Service`
- Desde cualquier `View` *(si utilizas el modelo xml)*
- Desde cualquier `Composable`
- O cualquier clase que extienda de `Context`

Existen **dos métodos** para acceder al contexto. Cada uno de ellos **devuelve** un **contexto diferente** y las principales diferencias son las siguientes:

|`getContext()` (en views xml) | `getApplicationContext()` |
|---|---|
|Contexto ligado a la Activity|Contexto ligado a toda la Aplicación |
|Depende del ciclo de vida de la Activity |Depende del ciclo de vida de la Aplicacion|
|Si muere la activty el context tambien|Todas las actividades tienen acceso al mismo contexto (aparte del suyo propio)|
|Cada activty tiene el suyo propio | |


---
## Usos

A continuación detallaré como se utiliza el context para varias tareas.


### Iniciar Activity 

Si vamos a **iniciar una actividad** diferente a la que se está ejecutando, deberemos hacer uso del **`Context`.**

En el ejemplo accederemos al **context** desde un **Composable**, en dicho composable tendremos acceso al **contexto** de la **activity** *(es decir que dependerá del lifecycle de la activity)* utilizando `LocalContext.current`.

Por ejemplo vamos a querer ejecutar en determinado momento la actvity `SecondActivity`

```kotlin
class SecondActivity : ComponentActivity() {  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        
        setContent {  
            Text("Esta es la segunda actividad")  
        }  
    }  
}
```

La actividad principal, `MainActivity` contiene un único `Composable`
```kotlin
class MainActivity : ComponentActivity() {  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
        
        setContent {  
            MyComposable()  
        }  
    }  
}
```

La  implementación del `Composable` que se utiliza en la actividad principal:
```kotlin
@Composable  
fun MyComposable() {  
    val context = LocalContext.current  
  
    Button(onClick = {  val intent = 
	    Intent(context, SecondActivity::class.java)  
        context.startActivity(intent) }
    ) {  
        Text("Iniciar Activity")  
    }  
}
```
En este ejemplo nuestro composable tiene un **botón** cuya única función es **obtener el contexto** y **ejecutar la `SecondActivity`**. 

Al ejecutarse accedemos al contexto vinculado a la activity para poder iniciar una segunda actividad en caso de que el usuario pulse el botón.

Si se ha iniciado la segunda actividad y, por cualquier motivo, el SO decide detener la primera actividad, el contexto utilizado en `MyComposable` dejará de ser válido. Por este motivo, es importante evitar enviar el mismo contexto a la segunda actividad *(mediante un Bundle)*, para prevenir posibles problemas relacionados con la gestión incorrecta del ciclo de vida del contexto y posibles fugas de memoria.

> En Jetpack Compose se suele utilizar una única actividad para la aplicación.

----

### Iniciar Servicios

Si queremos ejecutar un servicio en segundo plano *(background)* o en primer plano *(foreground)* también usaremos el `Context`.

Tenemos el siguiente servicio:
```kotlin
class MyBackgroundService : Service() {  
    override fun onBind(intent: Intent?): IBinder? {  
        return null  
    }  
  
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {  
        // { ... la logica del servicio }  
        return START_STICKY  
    }  
}
```

Su ejecución dentro de una actividad sería de la siguiente forma
```kotlin
class MainActivity : ComponentActivity() {  
    override fun onCreate(savedInstanceState: Bundle?) {  
        super.onCreate(savedInstanceState)  
  
        // Iniciar el servicio  
        val intent = Intent(this, MyBackgroundService::class.java)  
  
		startService(intent)  
    }  
}
```

En este caso el contexto lo utilizamos para instanciar un `Intent` (que este a su vez ejecutará el servicio). El primer parámetro del `Intent` es el contexto, como `ComponentActivity` extiende de la clase Context, se puede referenciar la misma clase *(MainActivity)* mediante `this`.

---

## Utilizarlo en Composables

En el apartado [Iniciar Activity](#iniciar-activity) se muestra como utilizar el contexto dentro de un composable, la implementación es de la siguiente forma:

```kotlin
@Composable  
fun MyComposable() {  
    val context = LocalContext.current  
	...
}
```
Esta es la forma en la que accedemos al contexto dentro de un composable, dicha forma nos devolverá el contexto ligado a la activity a la que pertenece dicho composable.

---

## Utilizarlo en ViewModels

Al utilizar el patrón de diseño MVVM **no** deberíamos **utilizar** el **Context** dentro del **ViewModel** ya que podría haber **fugas de memoria** y otra razón es mantener la **separación** de **responsabilidades**. También nos ayuda a mantener el código y testearlo mucho mas fácil.

El **ViewModel** solo debe encargarse de **almacenar datos** relacionados con la **vista** (el composable) y **manejar** los **datos** de la vista pero sin implementar el manejo de dichos datos. 

Es decir que él **no** debe **manejar** el **acceso** a una **API** o una **BBDD** o a cualquier recurso del sistema Android. 

El ViewModel solo implementará la **lógica ligada** a la **IU** y la implementación la hará un Repository y el ViewModel hará uso del Repository.

Si se necesita utilizar el context dentro del ViewModel se hará de la misma forma, con un Repository que implemente las acciones necesarias y en el ViewModel se utilizará el Repository *(inyectándolo por ejemplo)*.


> **PRACTICA POCO RECOMENDADA!**

> Si realmente quieres utilizarlo dentro del ViewModel puedes utilizar inyección de dependencias con Hilt por ejemplo e inyectar el Context en el ViewModel

----


## Referencias

{% embed https://developer.android.com/reference/android/content/Context#getApplicationContext() %}

{% embed https://amitshekhar.me/blog/context-in-android-application %}

{% embed https://medium.com/@banmarkovic/what-is-context-in-android-and-which-one-should-you-use-e1a8c6529652 %}