Prácticas Aplicadas para Evitar ANRs (Application Not Responding) – Sprint 3 - 5x5x5-cube/vinilos-app GitHub Wiki

Durante el desarrollo del Sprint 3 del proyecto Vinilos App, se continuaron aplicando buenas prácticas para evitar errores del tipo ANR (Application Not Responding), garantizando que todas las operaciones intensivas en red o base de datos se realicen en hilos apropiados, manteniendo el hilo principal libre para tareas de UI.

A continuación, se describen las principales prácticas observadas en las historias de este sprint:

1. Separación clara entre lógica de UI y lógica de negocio

Todas las operaciones de red se realizan desde los ViewModels y nunca desde las vistas (CreateAlbumScreen, AddTrackScreen, CollectorDetailScreen). Esto respeta el principio de separación de responsabilidades y evita ejecutar código pesado directamente en la capa de presentación.

2. Envío de resultados a la UI mediante LiveData

Para evitar congelamientos o demoras en la interfaz, los resultados se propagan a través de LiveData y se observan desde las vistas de forma reactiva:

Copiar
Editar
val createSuccess: LiveData<Boolean> = _createSuccess
val collector: LiveData<CollectorDetails> = _collector
Esto permite que los cambios se reflejen en pantalla solo cuando estén listos, sin bloquear la renderización ni forzar esperas activas.

3. Manejo preventivo de errores

Cada bloque de código que ejecuta operaciones potencialmente fallidas (como llamadas HTTP o acceso a base de datos) está protegido con try-catch, lo que evita bloqueos inesperados o interrupciones del flujo que podrían derivar en un ANR:

Copiar
Editar
try {
    albumsRepository.createAlbum(album)
    _createSuccess.value = true
} catch (e: Exception) {
    _error.value = e.message ?: "Error creating album"
}

4. Uso de viewModelScope y Dispatchers.IO en llamadas de red

Tanto en CreateAlbumViewModel.kt, CreateTrackViewModel.kt y CollectorDetailsViewModel.kt, las operaciones que interactúan con el repositorio y la base de datos se ejecutan dentro de una corrutina usando viewModelScope con el despachador IO o Default. Esto asegura que las tareas pesadas (como crear un álbum o consultar un coleccionista) no bloqueen el hilo principal.

Copiar
Editar
viewModelScope.launch(Dispatchers.IO) {
    albumsRepository.createTrack(albumId, _name.value!!, _duration.value!!)
}

O mediante withContext(Dispatchers.IO) dentro de un Dispatchers.Default:

Copiar
Editar
viewModelScope.launch(Dispatchers.Default) {
    withContext(Dispatchers.IO) {
        val data = collectorsRepository.getCollectorDetail(id)
        _collector.postValue(data)
    }
}
⚠️ **GitHub.com Fallback** ⚠️