Taula de continguts

Android RecyclerView

RecyclerView és l'objecte adequat per a visualitzar llargues llistes d'objectes en les darreres versions d'Android. Similarment a Android ListVieẉ però amb un funcionament una mica més sofisticat, la idea segueix sent reciclar les «targetes» de visualització de cada item per estalviar RAM. Seguint el paradigma MVC, necessitarà un objecte intermig Adapter que ens enllaça la part gràfica amb la part de model.

Referències:

, , , , , , , , ,

Reciclatge d'elements gràfics

recycling-items.jpg

MVC ampliat i Adapter

listview-adapter.jpg


Implementar una RecyclerView

Exemple: agenda de contactes

Volem fer una aplicació d'agenda de contactes simple. Amb nom i telèfon n'hi haurà prou per al model de contacte.

Seguirem les indicacions de la doc oficial d'Android de RecyclerView.

Haureu de crear els següents arxius o objectes:

Us deixo algunes pistes per facilitar la implementació:

  1. Crear un dataset d'exemple a MainActivity: el més senzill seria una ArrayList<Contact>.
    • Per les dades podeu crear un array amb 10 noms i un altre amb 10 cognoms i que els vagi combinant aleatòriament entre ells amb un num de telèfon random entre 100000000 i 999999999.
    • Crea al menys 40 contactes per comprovar el resultat de la visualització del RecyclerView.
  2. Crear classes Contact i ContactAdapter. Podeu fer click dret sobre la carpeta principal del projecte i fer New → Kotlin Class/File.
  3. Creeu el codi del Contact: com a mínim ha de tenir nom i telèfon.
  4. Insertar una RecyclerView al main tempate de l'Activity (a activity_main.xml).
  5. Eliminar TextView del main template per evitar confusions de IDs, o com a mínim modificar el seu ID amb un nom que no sigui el típic textView per quelcom més particularitzat.
  6. Afegir un layout per als elements del RecyclerView : text_row_layout.xml si voleu seguir la nomenclatura de la doc o contact_item.xml podria ser més adequat. Podeu crear-lo amb el botó dret sobre res → layout i fer New → Layout Resource File.
    • Canvieu la ConstraintLayout per una simple LinearLayout vertical.
    • Afegiu TextViews pels elements que hagueu posat a la classe Contact: nom i telèfon com a mínim.
  7. Posar-hi el codi del CustomAdapter de la doc al ContactAdapter (canviant el nom de la class). Adapteu el què us calgui, en particular el nom dels camps a visualitzar: nom i telèfon (a l'exemple només hi ha 1 camp).
  8. Adapteu el codi segons calgui.

Si no veieu elements de la llista al RecyclerView, revisa:

  1. Que hagis posat un LayoutManager al codi de l'Activity, sense aquest element no funciona el RecyclerView (l'exemple de la doc oficial no el té).
  2. Que el RecyclerView no estigui massa ajustat al top del layout de la Activity. Posa un marge més gran perquè la StatusBar pot amagar els elements.
  3. Vigila que no tinguis elements gràfics dels diferents layouts amb un mateix ID, en particular el del textView.

Un cop en funcionament, pots sofisticar la visualització:

  1. Millorant els item_layout.xml i afegint-hi elements com ImageView, etc.
  2. Prova amb la GridLayoutManager enlloc del LinearLayoutManager.


Exercicis

Mini Agenda

Implementa una agenda de contactes com s'ha descrit mes amunt.

Afegeix un botó flotant o Floating Action Button (FAB) com es descriu a la doc. El botó ens obrirà un Dialog per afegir un nou contacte.

Galeria d'imatges

Implementa una aplicació de captació d'imatges com la descrita a Android Camera que s'enregistrin en l'espai d'emmagatzematge compartit de l'aplicació.

Visualitza les imatges enregistrades en una nova Activity que visualitzi a mode de «galeria d'imatges» pròpies de la nostra app.

El dataset pot ser una llista d'elements File que podem llistar de l'espai d'emmagatzematge compartit de la nostra aplicació.


Implementar onClick (amb funcions lambda)

La implementació amb funcions lambda és més sofisticada, i té l'avantatge de tenir el codi més curt.

Per implementar un onClick cal modificar:

A l'Adapter afegim un nou atribut onItemClick al constructor:

CustomAdapter.kt
class MyAdapter(
    private val dataList: List<String>,
    private val onItemClick: (Int) -> Unit
) : RecyclerView.Adapter<MyViewHolder>() {
 
    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        holder.itemView.setOnClickListener {
            onItemClick(position)
        }
    }
}

A la instanciació de l'Adapter dins la Activity afegim la funció lambda que ens retorna la position del l'element clicat:

MainActivity.kt
val adapter = MyAdapter(dataList) { position ->
    // Manejar el clic aquí
    Toast.makeText(this, "Clic: $position", Toast.LENGTH_SHORT).show()
}