Guía de Asincronía en Android: De AsyncTask (Legacy) a Corrutinas en Jetpack Compose

- 👤 Andrés Cruz

🇺🇸 In english

Guía de Asincronía en Android: De AsyncTask (Legacy) a Corrutinas en Jetpack Compose

Cuando se desea realizar un llamado asíncrono en entornos web, solemos recurrir a AJAX o Fetch. En Android, aunque el concepto es similar, la ejecución es más compleja debido a la gestión de hilos y el ciclo de vida del dispositivo.

Enfoque Moderno: Corrutinas de Kotlin y Jetpack Compose

Hoy en día, la forma recomendada de manejar la asincronía es mediante Kotlin Coroutines. A diferencia de los hilos tradicionales, las corrutinas son ligeras y, lo más importante, son conscientes del ciclo de vida.

Uso de ViewModel y viewModelScope

En lugar de declarar la tarea dentro de la vista, la lógica se mueve a un ViewModel. Esto permite que la petición sobreviva a la rotación de pantalla.

// Enfoque moderno en el ViewModel
class MyViewModel : ViewModel() {
    var uiState by mutableStateOf<String?>(null)
        private set

    fun fetchData() {
        viewModelScope.launch {
            // Esto se ejecuta en segundo plano sin bloquear la UI
            val result = repository.makeNetworkCall() 
            uiState = result // Se actualiza el estado automáticamente
        }
    }
}

Implementación en Jetpack Compose

En Jetpack Compose, la interfaz reacciona automáticamente a los cambios de estado. Ya no necesitamos interfaces de respuesta (delegates); la UI simplemente se "re-compone" cuando llega la data.

@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
    val state = viewModel.uiState

    Column {
        if (state == null) {
            CircularProgressIndicator() // Cargando...
            LaunchedEffect(Unit) { viewModel.fetchData() }
        } else {
            Text(text = "Resultado: $state")
        }
    }
}

Simulando la opción "Deshacer" (Undo)

El caso de uso de "Deshacer" de Gmail es un ejemplo perfecto para las corrutinas. En lugar de complejos hilos que duermen, usamos la función delay() de Kotlin, que no bloquea el hilo principal.

fun deleteItemWithUndo(item: Item) {
    viewModelScope.launch {
        showUndoSnackbar = true
        try {
            // Esperamos 5 segundos de forma asíncrona
            withTimeout(5000) {
                // Si el usuario no cancela en este tiempo...
                repository.deletePermanently(item)
            }
        } catch (e: CancellationException) {
            // Si el usuario presiona "Deshacer", cancelamos la corrutina
            showUndoSnackbar = false
        }
    }
}

Enfoque Legacy: AsyncTask y Threads manuales

Históricamente, en Android se utilizaban los Thread manuales o la clase AsyncTask (ahora obsoleta) para ejecutar tareas en segundo plano dentro de una Actividad o Fragment:

// Forma Legacy con Threads
new Thread(new Runnable() {
    public void run() {
        // Tareas costosas aquí
    }
}).start();

Problemas del enfoque Legacy

El mayor problema es el Ciclo de Vida. Si el usuario rota la pantalla (provocando un recreate de la actividad) o navega hacia atrás mientras la petición está en curso, se producen fugas de memoria (memory leaks) o la petición simplemente "se pierde" al intentar actualizar una interfaz que ya no existe.

Para mitigar esto en el modelo Legacy, se solían implementar interfaces como AsyncResponse para delegar el resultado, pero la complejidad del código aumentaba exponencialmente al intentar manejar los cambios de configuración.

public class MyFragment extends Fragment implements
		AsyncResponse {

...
myAsyncTask = new MyAsyncTask();
…

	public void processFinish(String output) {
//El método processFinish() es invocado cuando la clase 
//asíncrona llamada MyAsyncTask ejecuta el método onPostExecute(result) method.
	}
}

Conclusión

Mientras que el enfoque Legacy nos obligaba a pelear contra el ciclo de vida de la Actividad, el enfoque de Compose y Corrutinas nos permite escribir código asíncrono que parece secuencial, siendo mucho más robusto y fácil de mantener.

Acepto recibir anuncios de interes sobre este Blog.

Domina la programación asíncrona en Android: de los hilos y AsyncTask (Legacy) a las potentes Corrutinas de Kotlin y Jetpack Compose.

| 👤 Andrés Cruz

🇺🇸 In english