certmundo.
es‑mx

7 min de lectura

¿Cómo usar RecyclerView para mostrar listas de datos en Android?

RecyclerView es el componente estándar de Android para mostrar listas largas de forma eficiente, reutilizando las vistas que ya no están visibles en pantalla.

Cuando tienes 500 productos de Liverpool o 1,000 pedidos de Mercado Libre, no puedes crear una vista por cada elemento. RecyclerView resuelve ese problema reciclando las filas que el usuario ya scrolleó.

¿Por qué RecyclerView y no ListView?

ListView es el componente anterior y no recicla vistas de forma automática ni eficiente. RecyclerView obliga a usar el patrón ViewHolder, que mantiene referencias a las vistas en memoria y evita llamadas costosas a findViewById() en cada scroll.

El resultado es una lista fluida incluso con miles de elementos.

Las tres piezas principales

RecyclerView funciona con tres componentes que trabajan juntos:

Componente Responsabilidad
RecyclerView Contenedor en el layout XML
ViewHolder Guarda referencias a las vistas de cada fila
Adapter Une los datos con el ViewHolder

No puedes tener uno sin los otros dos.

Paso 1: Agregar la dependencia

Abre tu archivo build.gradle (Module: app) y agrega:

dependencies {
    implementation "androidx.recyclerview:recyclerview:1.3.2"
}

Sincroniza el proyecto con Sync Now. Sin esta línea, Android Studio no reconocerá el componente.

Paso 2: Declarar RecyclerView en el layout

En tu archivo activity_main.xml, agrega el componente:

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/recyclerProductos"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="8dp" />

Este RecyclerView ocupará toda la pantalla y mostrará la lista de productos.

Paso 3: Crear el layout de cada fila

Crea un nuevo archivo XML llamado item_producto.xml en la carpeta res/layout/:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:padding="12dp">

    <TextView
        android:id="@+id/tvNombreProducto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="16sp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/tvPrecioProducto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="14sp"
        android:textColor="#2E7D32" />

</LinearLayout>

Este layout define cómo se ve una sola fila de la lista. Cada fila muestra nombre y precio.

Paso 4: Crear el modelo de datos

Antes de construir el Adapter, necesitas una clase que represente cada elemento. Crea una data class:

data class Producto(
    val nombre: String,
    val precio: Double
)

Esta clase modela un producto con nombre y precio, como los que vende Liverpool o Bimbo en sus apps.

Paso 5: Crear el Adapter con ViewHolder

Esta es la parte central. Crea una nueva clase ProductoAdapter.kt:

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView

class ProductoAdapter(
    private val productos: List<Producto>
) : RecyclerView.Adapter<ProductoAdapter.ProductoViewHolder>() {

    // ViewHolder: guarda referencias a las vistas de una fila
    inner class ProductoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val tvNombre: TextView = itemView.findViewById(R.id.tvNombreProducto)
        val tvPrecio: TextView = itemView.findViewById(R.id.tvPrecioProducto)
    }

    // Infla el layout de la fila y crea el ViewHolder
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductoViewHolder {
        val vista = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_producto, parent, false)
        return ProductoViewHolder(vista)
    }

    // Llena las vistas con los datos del elemento en la posición dada
    override fun onBindViewHolder(holder: ProductoViewHolder, position: Int) {
        val producto = productos[position]
        holder.tvNombre.text = producto.nombre
        holder.tvPrecio.text = "$${String.format("%,.0f", producto.precio)}"
    }

    // Devuelve el total de elementos en la lista
    override fun getItemCount(): Int = productos.size
}

El Adapter tiene tres métodos obligatorios: onCreateViewHolder, onBindViewHolder y getItemCount. Si omites uno, el código no compilará.

Paso 6: Conectar todo en la Activity

En tu MainActivity.kt, inicializa el RecyclerView con el Adapter y un LayoutManager:

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Lista de productos con precios en pesos
        val productos = listOf(
            Producto("Laptop Bimbo Edition", 18500.0),
            Producto("Pantalla Liverpool 55\"", 12300.0),
            Producto("Bocina FEMSA Pro", 3200.0),
            Producto("Teclado Mercado Libre", 850.0),
            Producto("Mouse inalámbrico", 450.0)
        )

        val recycler = findViewById<RecyclerView>(R.id.recyclerProductos)

        // LinearLayoutManager muestra los elementos uno debajo del otro
        recycler.layoutManager = LinearLayoutManager(this)
        recycler.adapter = ProductoAdapter(productos)
    }
}

Al correr la app, verás cinco productos listados con sus precios formateados. El output en pantalla se ve así:

Laptop Bimbo Edition
$18,500

Pantalla Liverpool 55"
$12,300

Bocina FEMSA Pro
$3,200

Teclado Mercado Libre
$850

Mouse inalámbrico
$450

Agregar clic en cada elemento

Una lista sin interacción es poco útil. Agrega un listener al Adapter para detectar qué producto tocó el usuario:

class ProductoAdapter(
    private val productos: List<Producto>,
    private val onItemClick: (Producto) -> Unit
) : RecyclerView.Adapter<ProductoAdapter.ProductoViewHolder>() {

    inner class ProductoViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val tvNombre: TextView = itemView.findViewById(R.id.tvNombreProducto)
        val tvPrecio: TextView = itemView.findViewById(R.id.tvPrecioProducto)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductoViewHolder {
        val vista = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_producto, parent, false)
        return ProductoViewHolder(vista)
    }

    override fun onBindViewHolder(holder: ProductoViewHolder, position: Int) {
        val producto = productos[position]
        holder.tvNombre.text = producto.nombre
        holder.tvPrecio.text = "$${String.format("%,.0f", producto.precio)}"

        // Asigna el clic al layout completo de la fila
        holder.itemView.setOnClickListener {
            onItemClick(producto)
        }
    }

    override fun getItemCount(): Int = productos.size
}

En la Activity, pasa la lambda al crear el Adapter:

recycler.adapter = ProductoAdapter(productos) { producto ->
    // Muestra el nombre del producto seleccionado
    Toast.makeText(this, "Seleccionaste: ${producto.nombre}", Toast.LENGTH_SHORT).show()
}

Este patrón de lambda como callback es el más común en proyectos profesionales de Android en México y en todo el mundo.

Errores comunes

Error 1: Olvidar asignar el LayoutManager. Si no escribes recycler.layoutManager = LinearLayoutManager(this), la lista no mostrará nada. El RecyclerView necesita saber cómo organizar los elementos.

Error 2: No inflar el layout correcto en onCreateViewHolder. Si usas R.layout.activity_main en lugar de R.layout.item_producto, la app mostrará vistas incorrectas o lanzará una excepción en tiempo de ejecución.

Error 3: Modificar la lista original fuera del Adapter sin notificar. Si agregas o quitas elementos a productos sin llamar a notifyDataSetChanged() o notifyItemInserted(position), la pantalla no se actualiza. El Adapter no detecta cambios automáticamente en una List simple.

Error 4: Hacer operaciones pesadas dentro de onBindViewHolder. onBindViewHolder se llama constantemente mientras el usuario hace scroll. Cálculos complejos o llamadas a red en ese método generan lag visible. Prepara los datos antes de pasarlos al Adapter.

Tipos de LayoutManager disponibles

LayoutManager Resultado visual
LinearLayoutManager Lista vertical u horizontal
GridLayoutManager(ctx, 2) Cuadrícula de 2 columnas
StaggeredGridLayoutManager Cuadrícula con alturas variables

Para un catálogo de productos como el de Liverpool, GridLayoutManager con 2 columnas es la opción más común.

Puntos clave

Puntos clave

  • RecyclerView requiere tres componentes obligatorios: el widget en XML, un **ViewHolder** que guarda referencias a las vistas de cada fila, y un **Adapter** que une los datos con el ViewHolder.
  • El Adapter debe implementar tres métodos: `onCreateViewHolder` para inflar el layout de la fila, `onBindViewHolder` para llenar los datos, y `getItemCount` para indicar el total de elementos.
  • Siempre asigna un **LayoutManager** antes de que la lista sea visible; sin él, RecyclerView no renderiza ningún elemento aunque el Adapter esté correctamente configurado.
  • Pasa una **lambda como parámetro** al Adapter para manejar el clic en cada fila sin acoplar la lógica de navegación dentro del Adapter.
  • Llama a `notifyDataSetChanged()` o a los métodos específicos como `notifyItemInserted(position)` cada vez que modifiques la lista de datos, para que RecyclerView actualice la pantalla.

Comparte esta lección:

¿Cómo usar RecyclerView para mostrar listas de datos en Android? | Kotlin para Android: Curso Práctico | Certmundo