Android Kotlin

Cet article explique comment afficher la liste des versions Android via un RecyclerView, en Android avec le langage Kotlin.

Le RecyclerView est un composant visuel Android de type conteneur. Ce type de vue permet d’afficher un tableau d’éléments (ici le tableau des versions Android), sous forme de liste ou de grille. Il fonctionne avec un adaptateur ou adapter.

De manière générale, le concept d’adaptateur en Android permet de faire le lien entre la vue et les données.

L’implémentation se fait en trois étapes :

Implémentation liée aux données

Implémentation de l’adaptateur

Configuration de l’adaptateur avec sa vue

Implémentation liée aux données

Tout d’abord, il s’agit de mettre en place l’Activity principale.

Ensuite, il s’agit de créer une classe représentant nos éléments à afficher. Plus précisément, il s’agit de créer une classe de donnée représentant une version d’Android. Pour commencer, notre version d’Android ne possède qu’un nom (name).

Puis, il s’agit de réaliser les implémentations liées aux données. En particulier, un tableau d’éléments, soit un tableau de versions Android, va être déclaré dans l’Activity principale, ce dernier contient les données à afficher.

  1. Créez un nouveau projet Android Studio, dont l’Activity principale est MainActivity, avec le modèle EmptyActivity.

  2. Créez un nouveau fichier Kotlin contenant une data class, nommons la AndVersion :

     data class AndVersion(var name: String)
    

    Cette dernière permet de créer des objets de type AndVersion ayant un nom, “Lollipop”, par exemple val loli = AndVersion("Lollipop").

    Note : L’intérêt d’utiliser une classe de donnée est la génération automatique de fonction d’affichage tel que toString(), de copie d’objet, copy(), d’égalité, equals(), etc [1].

  3. Créez le tableau d’éléments dans la classe MainActivity :

     val andVersionArray = arrayOf(AndVersion("Banana"), AndVersion("Lollipop"))
    

À présent, les données sont créées, présentes dans le tableau andVersionArray. Il s’agit, à présent, d’implémenter un adaptateur de données pour le composant visuel RecyclerView, soit une classe héritant de RecyclerView.Adapter.

Implémentation de l’adaptateur

Dans cette partie, il faut créer la vue d’un élément de la liste, soit la vue d’une version Android. Ensuite, il s’agit de créer un adaptateur pour la liste de versions Android. En particulier, nous allons créer une classe héritant de RecyclerView.Adapter.

  1. Ajoutez le fichier item_and_version.xml, la vue représentant une ligne, dans le dossier res/layout/ :

     <LinearLayout
         xmlns:android="http://schemas.android.com/apk/res/android"
         xmlns:app="http://schemas.android.com/apk/res-auto"
         android:layout_width="match_parent"
         android:layout_height="@dimen/common_width">
    
         <TextView
             android:id="@+id/andVersionTxt"
             android:layout_width="@dimen/common_width"
             android:layout_height="@dimen/common_width" />
    
         <View
             android:layout_width="match_parent"
             android:layout_height="1dp"
             android:background="@color/colorPrimaryDark" />
     </LinearLayout>
    

    Remarquez la valeur match_parent, pour les attributs android:layout_width et android:layout_height, cela signifie que la hauteur et la largeur doit correspondre au parent.

  2. Inclure la bibliothèque du RecyclerView dans le fichier build.gradle (Module: app) :

     implementation 'androidx.recyclerview:recyclerview:1.0.0'
    
  3. Déclarez une classe héritant de RecyclerView.Adapter

     class AndVersionAdapter(val items: Array<AndVersion>) : RecyclerView.Adapter<AndVersionAdapter.ViewHolder>() {
    
     }
    
  4. Ajoutez, dans la classe AndVersionAdapter, la composition (la inner class) :

     class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
                
         }
    
  5. Ajoutez les méthodes d’héritage pour AndVersionAdapter :

    la fonction retournant le nombre d’éléments de la liste :

     override fun getItemCount(): Int = items.size
    

    la fonction retournant la visualisation d’une ligne de la liste :

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

    la fonction s’occupant de charger les données dans la vue :

     override fun onBindViewHolder(holder: ViewHolder, position: Int) {
     }
    
  6. Ajoutez, dans le ViewHolder de AndVersionAdapter, la fonction qui permet de lier les données à la vue :

     class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
             fun bindAndVersion(andVersion: AndVersion) {
                 with(andVersion) {
                     itemView.andVersionTxt.text = "$name"
                 }
             }
         }
    
  7. Implémentez alors la méthode de AndVersionAdapter de cette façon :

     override fun onBindViewHolder(holder: ViewHolder, position: Int) {
             holder.bindAndVersion(items[position])
     }
    

Remarque : Certains éléments, noms de classe, sont en rouge, il s’agit d’importer les classes manquantes (via le raccourcis clavier alt + Enter).

À présent, l’implémentation de l’adaptateur est complète, il ne reste plus qu’à l’utiliser.

Configuration de l’adaptateur avec sa vue

À présent, il s’agit de déclarer dans la vue principale le RecyclerView, andVersionRecyclerView. Puis, il s’agira de configurer andVersionRecyclerView. En effet, il a besoin d’un gestionnaire d’agencement, LinearLayoutManager, ainsi que d’un adaptateur, AndVersionAdapter.

  1. Déclarez le composant RecyclerView dans la vue principale, activity_main.xml :

     <androidx.recyclerview.widget.RecyclerView
         xmlns:android="http://schemas.android.com/apk/res/android"
         android:id="@+id/andVersionRecyclerView"
         android:layout_width="match_parent"
         android:layout_height="match_parent" />
    
    
  2. Spécifiez un LinearLayoutManager pour l’objet andVersionRecyclerView, dans la méthode onCreate(), de l’Activity principale :

     andVersionRecyclerView.layoutManager = LinearLayoutManager(this)
    
  3. Spécifiez l’adaptateur pour l’objet andVersionRecyclerView, toujours dans la méthode onCreate(), de l’Activity principale :

     andVersionRecyclerView.adapter = AndVersionAdapter(andVersionArray)
    

    À présent, l’Activity principale MainActivity déclare un RecyclerView, andVersionRecyclerView. Ce dernier est configuré avec l’adaptateur AndVersionAdapter. Ici, vous devriez pouvoir exécuter le projet.

Plus loin

Avec cette première version, l’affichage de la vue via le ViewHolder n’est pas parfaitement optimale [5](cela est dû au côté obscur des extensions Kotlin). Afin d’y remédier, il faut, tout d’abord, autoriser les expérimentations avec les extensions Kotlin dans la partie android du fichier graddle (module) :

 androidExtensions {
        experimental = true
    }

Ensuite, il s’agit :

  • d’ajouter LayoutContainer comme une interface du ViewHolder, relatif à l’Adapter
  • d’initialiseer la constante containerView
    class ViewHolder(val view: View) : RecyclerView.ViewHolder(view), LayoutContainer {
          override val containerView: View?
              get() = itemView
    

    Enfin, il n’y a plus qu’à enlever les appels à itemView, soit :

    andVersionName.text = name
    

    L’import de la vue import kotlinx.android.synthetic.main.item_and_version.view.* devient import kotlinx.android.synthetic.main.item_and_version.*.

En outre, il est possible d’utiliser une fonction d’extension pour charger la vue dans la méthode onCreateViewHolder() de la classe AndVersionAdapter :

fun ViewGroup.inflate(@LayoutRes layoutRes: Int, attachToRoot: Boolean = false): View {
       return LayoutInflater.from(context).inflate(layoutRes, this, attachToRoot)
}

La méthode onCreateViewHolder() devient alors :

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): AndVersionAdapter.ViewHolder {
    return ViewHolder(parent.inflate(R.layout.item_and_version))
}

Pour le moment seul le titre de la version s’affiche, il est possible d’ajouter une image.

Ajoutez l’élément graphique dans le fichier item_and_version.xml :

  <ImageView
      android:id="@+id/andVersionImg"
      android:layout_width="@dimen/common_width"
      android:layout_height="@dimen/common_width" />

Ajoutez l’attribut img dans la classe AndVersion :

data class AndVersion(var name: String, var img:Int)

Ajoutez les images dans le dossier res/drawable/.

Ajoutez le tableau de chaîne de caractères, dans strings.xml :

<string-array name="andVersionName">    
  <item>Cupcake</item>    
  <item>Donut</item>    
  <item>Eclair</item>
</string-array>

Ajoutez une fonction seedItems(), son rôle est d’initialiser les tableaux :

var nameArray = resources.getStringArray(R.array.andVersionName)
val imgArray = intArrayOf(R.drawable.cupcake, R.drawable.donut, R.drawable.eclair)
for (i in 0..(nameArray.size-1))
            andVersionArray[i] = AndVersion(nameArray[i], imgArray[i])

andVersionArray devient dynamique, il est initialisé au cours de l’exécution de l’application (cf. AK-2 pour initialiser un tableau en Kotlin). Il est alors initialisé comme suit :

val andVersionArray = mutableListOf<AndVersion>()

Le paramètre du constructeur de AndVersionAdapter devient alors :

val items: MutableList<AndVersion>

Remarque : Le tableau imgArray doit être de taille égale (ou supérieure) à nameArray afin que l’index i ne dépasse pas les capacités de imgArray.

Faites le lien entre la vue d’une ligne et la donnée dans le ViewHolder de l’adaptateur :

itemView.andVersionImg.setImageResource(img)

Il est aussi possible d’intercepter le clique sur l’image depuis le ViewHolder :

andVersionImg.setOnClickListener { itemView.context.toast("$name")}

Il est possible, dans certain cas, que les données de l’adaptateur change. À ce moment, la méthode notifyDataSetChanged() est utilisée sur l’objet de type adapter, ici andVersionRecyclerView.adapter.

Finalement, en trois quart d’heure top chrono il est possible d’implémenter un RecyclerView. Cela dit, c’est une implémentation qui demande à être pratiquée afin d’être parfaitement maîtrisée, selon les trois étapes d’implémentation :

Implémentation liée aux données

Implémentation de l’adaptateur

Configuration de l’adaptateur avec sa vue

L’intérêt d’utiliser un RecyclerView est de pouvoir, comme son nom l’indique, recycler les lignes à afficher. Ces dernières sont stockées en cache via le ViewHolder.

La complexité de ce développement réside dans l’appréhension du concept d’adaptateur. Ce concept est récurrent en Android, il s’applique avec des vues de type conteneur, comme le GridView, le ViewPager, le Spinner, etc. Chacune de ces vues possède son type d’adaptateur (RecyclerView.Adaptateur, FragmentStatePagerAdapter, SpinnerAdapter, etc.). L’adaptateur peut parfois être utilisé tel quel, sans être hérité comme on l’a fait dans cet article. Par exemple, avec le Spinner, il suffit d’indiquer un tableau de chaîne de caractère dans le constructeur de SpinnerAdapter.

En outre, la démonstration de cette liste de version Android est disponible dans la partie “Version Android” de l’application Kotlin pour Android sur Play Store.

Références

  1. Documentation Kotlin : Data classes
  2. Merge Request 6 Item List Adapter
  3. Merge Request 6 Shortcuts List Adapter
  4. Antonio Leiva: RecyclerView in Android: The basics
  5. Kotlin Android Extensions: Using View Binding the right way

Partagez ou réagissez sur Twitter.

Vous avez trouvé une erreur ou voulez améliorer cet article ? Editez le directement !

Comments