JG
Volver al blog

Guía Definitiva: Peticiones HTTP en Android con Jetpack Compose

¿Alguna vez has sentido que crear una App móvil es como construir una isla desierta? Sin conexión a internet, tu App está aislada. Como desarrolladores Fullstack, sabemos que el verdadero poder surge cuando nuestra interfaz consume datos de un backend robusto. Es la diferencia entre una app de juguete y una que en realidad aporte valor.

Hoy vamos a romper esa barrera. Te enseñaré cómo conectar una App de Android hecha con Jetpack Compose a una API externa usando Retrofit. Y no te preocupes, si nunca has tocado Android, esta guía está diseñada para que termines con algo funcionando. Más o menos. Jaja.

1. El Manifiesto y las Dependencias

Antes de escribir una sola línea de lógica, debemos pedir permiso. Android es celoso con la seguridad.

El Permiso de Internet

Abre tu archivo AndroidManifest.xml y, antes de la etiqueta <application>, agrega esta línea:

<uses-permission android:name="android.permission.INTERNET" />

Por defecto Android no permite que tu app se conecte a internet. Es una medida de seguridad para proteger a los usuarios. Salir a internet le da la capacidad de descargar datos, imágenes, videos, etc. Pero también le da la capacidad de enviar datos a internet y descargar información sensible, por eso la aplicación debe decirle a Android que va a utilizar esta función para que el sistema operativo se lo notifique al usuario.

Arquitectura Android
Es importante pedir permiso para utilizar internet

Instalando las herramientas (Gradle)

Retrofit no viene en la caja. Debes ir a tu archivo build.gradle.kts (el del módulo :app) y agregar estas librerías en la sección de dependencies:

dependencies {
    // Retrofit: El motor de nuestras peticiones
    implementation("com.squareup.retrofit2:retrofit:2.11.0")
    // Converter Gson: Para traducir JSON a objetos Kotlin automáticamente
    implementation("com.squareup.retrofit2:converter-gson:2.11.0")


    // Lifecycle ViewModel: Para que la clase ViewModel exista y funcione. ViewModel es una dependencia que se encarga de manejar la lógica de la aplicación y el estado de la UI.
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0")
    // ViewModel Compose: Para poder usar 'viewModel()' dentro de los Composables
    implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.0")
}

No olvides darle al botón de “Sync Now” en Android Studio.

2. El Modelo de Datos

Supongamos que queremos consultar información de un usuario. Necesitamos una “Data Class” que represente ese JSON. Es como crear una entidad en C# o un Struct en Go.

data class User(
    val id: Int,
    val name: String,
    val email: String
)

3. La Interfaz de la API (El Contrato)

Aquí es donde Retrofit brilla. No escribimos la implementación de la petición, solo definimos cómo se ve:

interface ApiService {
    @GET("users")
    suspend fun getUsers(): List<User>
}

El modificador suspend es vital: le dice a Kotlin que esta función se ejecutará de forma asíncrona sin congelar la pantalla del usuario.

Aquí podemos poner todos los métodos que queramos para hacer peticiones a la API. En el ejemplo estamos haciendo una petición GET a la ruta “users”, pero podríamos hacer peticiones POST, PUT, DELETE, etc.

4. El Objeto de Configuración

Necesitamos un lugar donde se cree la instancia de Retrofit. Lo haremos simple con un object (un Singleton en Kotlin):

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitClient {
private const val BASE_URL = "https://jsonplaceholder.typicode.com/"

    // el ApiService es una interfaz que definimos antes
    //lazy es para que se ejecute solo cuando se necesite
    val apiService: ApiService by lazy {
        Retrofit.Builder()
            .baseUrl(BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
            .create(ApiService::class.java)
    }

}

5. El ViewModel: El Cerebro

En Jetpack Compose, la UI no debe hacer peticiones directamente. Usamos un ViewModel para manejar la lógica y el estado.

class UserViewModel : ViewModel() {
// Estado de la lista de usuarios
var users by mutableStateOf<List<User>>(emptyList())
private set

    fun fetchUsers() {
        viewModelScope.launch {
            try {
                val response = RetrofitClient.apiService.getUsers()
                users = response
            } catch (e: Exception) {
                // Manejo de errores (puedes imprimir un log aquí)
            }
        }
    }

}

6. La Interfaz en Jetpack Compose

Finalmente, dibujamos la data. Usaremos un LaunchedEffect para disparar la petición cuando se cargue la pantalla por primera vez.

@Composable
fun UserListScreen(viewModel: UserViewModel = viewModel()) {
val users = viewModel.users

    LaunchedEffect(Unit) {
        viewModel.fetchUsers()
    }

    LazyColumn(modifier = Modifier.fillMaxSize().padding(16.dp)) {
        items(users) { user ->
            Column(modifier = Modifier.padding(bottom = 8.dp)) {
                Text(text = user.name, fontWeight = FontWeight.Bold)
                Text(text = user.email, color = Color.Gray)
                Divider()
            }
        }
    }

}

Dato para Ingenieros: LazyColumn es súper eficiente porque solo renderiza los elementos que están visibles en pantalla, ahorrando memoria y batería.

Importante, no olvides agregar este componente en tu MainActivity.kt, debe quedar algo así:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            UserListScreen()
        }
    }
}

Conclusión

Pasar de una App estática a una conectada es el primer paso para crear software de impacto. Dominar Retrofit + Compose te pone a la vanguardia del desarrollo móvil nativo en Android.

Arquitectura Android
Separar la lógica de la vista es lo que hace que tu código sea profesional.

¿Te gustaría que en el siguiente post veamos cómo manejar estados de “Cargando” o “Error” con una interfaz más bonita? ¡Házmelo saber en los comentarios!