How to use ViewBinding in a RecyclerView

In this article I would show you how to make use of viewBinding when setting up a RecyclerView, now this can be a little bit tricky and so can easily go wrong but I would try to break down every step along the way. In case you have no idea what viewBinding is about, you can check out my previous article where I introduced it and how to set it up both in an Activity and a Fragment. Using View binding to replace findViewById on Android

The following dependencies would be needed for this project make sure they are added to your project and gradle sync is successful

dependencies {
    .....
    .....
    .....


    //material Design for RecyclerView
    implementation 'com.google.android.material:material:1.3.0'

    //glide to load images from url
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    kapt 'com.github.bumptech.glide:compiler:4.11.0'
}

Do not also forget to set viewBinding to true in the same file where you just added dependencies

android {
    .....
    .....
    .....

    buildFeatures {
        viewBinding true
    }
}

Without wasting much of our time lets jump into code and create this RecyclerView, so start a new Android studio project, name it whatever you like when project sync is completed open up activity_main.xml file and add the following to it

<androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

Now that the RecyclerView has been added to the activity_main.xml file we need to define the xml layout file that would be used populating the views into the RecyclerView. Navigate to your res folder then to layout to create a new Layout Resource File I would name this file single_article_layout you can name yours whatever.

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <TextView
        android:id="@+id/articleTitle"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text=""
        android:textSize="10sp"
        android:textColor="#000000"
        android:layout_marginTop="5dp"
        android:layout_marginStart="5dp"
        android:layout_marginEnd="5dp"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>


    <ImageView
        android:id="@+id/articleImage"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        android:src="@drawable/ic_launcher_background.xml"
        android:scaleType="centerCrop"
        app:layout_constraintTop_toBottomOf="@id/articleTitle"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>


    <TextView
        android:id="@+id/articleDescription"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text=""
        android:textSize="10sp"
        android:textColor="#000000"
        android:layout_margin="5dp"
        app:layout_constraintTop_toBottomOf="@id/articleImage"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>

    <TextView
        android:id="@+id/articleAuthor"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:text=""
        android:textColor="#000000"
        app:layout_constraintBottom_toBottomOf="@id/articleImage"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent" />

    <TextView
        android:id="@+id/articlePublishedAt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:text=""
        android:textColor="#000000"
        app:layout_constraintBottom_toBottomOf="@id/articleImage"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent" />

    <TextView
        android:id="@+id/articleSource"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:text=""
        android:textColor="12sp"
        android:textColor="#42ABD8"
        app:layout_constraintTop_toBottomOf="@id/articleDescription"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent" />

    <View
        android:layout_width="match_parent"
        android:layout_height="@dimen/_1sdp"
        android:background="#ccc"
        app:layout_constraintTop_toBottomOf="@id/articleSource"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

From the xml layout above you can already tell that I would not be focusing on creating a beautiful UI but on the actual setup of the RecyclerView so please bear with me. Next on our agenda is creating a model class for our adapter that would be created in a while, create a new Kotlin data class and name it Article

data class Article(
    val author: String,
    val content: String,
    val description: String,
    val publishedAt: String,
    val source: String,
    val title: String,
    val urlToImage: String
)

Now we move to the main business which is the adapter, create a new Kotlin class named ArticleAdapter or whatever name you chose

class ArticleAdapter(
    private val articles: ArrayList<Article> 
) : RecyclerView.Adapter<ArticleAdapter.RecyclerViewHolder>() {

    inner class ArticleViewHolder(var binding: SingleArticleLayoutBinding): RecyclerView.ViewHolder(binding.root)


    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ArticleViewHolder {
        val binding = SingleArticleLayoutBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        )
        return ArticleViewHolder (binding)
    }

    override fun onBindViewHolder(holder: ArticleViewHolder , position: Int) {
        val article = articles[position]

        holder.binding.apply {
            Glide.with(this.root)
                .load(article.urlToImage)
                .placeholder(R.drawable.ic_launcher_background.xml)
                .into(articleImage)

            articleTitle.text = article.title
            articleDescription.text = article.description
            articleAuthor.text = article.author
            articlePublishedAt.text = article.publishedAt
            articleSource.text = article.source

            this.root.setOnClickListener {
                onItemClickListener?.let { it(article) }
            }
        }
    }

    override fun getItemCount(): Int {
        return articles.size
    }

    private var onItemClickListener: ((Article) -> Unit) ? = null

    fun setOnItemClickListener(listener: (Article) -> Unit) {
        onItemClickListener = listener
    }
}

The adapter is fully ready to be integrated but before that let me quickly explain what is happening there from top to bottom

  1. An ArrayList was passed into the constructor of the RecyclerView class, this list would actually be created inside of MainActivity.

  2. The ViewHolder class is created which is an inner class, the viewholder holds reference to all the views we have defined in the single_article layout. In the constructor of these class I passed SingleArticleLayoutBinding which is the binding class generated by the compiler for single_article_layout.xml file.

  3. In onCreateViewHolder method I called the inflate method of SingleArticleLayoutBinding class pass in the required arguments assign it to the variable called binding then return the viewholder.

  4. The onBindViewHolder method is where the views are bound to their respective data, you can see I used holder.binding.apply{} - holder and binding are instances of viewHolder and SingleArticleLayoutBinding but apply is a scope function in Kotlin I used to make the code more consise instead of repeatedly writing holder.binding for all the available views we make use of just one inside the apply block.

  5. An onClick listener that I would implement later to show a toast of the item clicked.

There you go just a summary of what the adapter did, now to the MainActivity.kt class for the final set of code

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
    private lateinit var adapter: ArticleAdapter
    private val articles = arrayListOf<Article>()


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)


        getArticles()
        adapter = ArticleAdapter(getArticles())  //Initializing the adapter and passing the list as an argument
        binding.recyclerView.apply {
            adapter = adapter //setting RecyclerViews adapter to the adapter initialized above
            layoutManager = LinearLayoutManager(this@MainActivity)
        }
        adapter.setOnItemClickListener {
            Toast.makeText(this@MainActivity, it.author, Toast.LENGTH_SHORT).show()
        }
    }


//This method is for generating the dummy list of Articles
    private fun getArticles(): ArrayList<Article>{
        articles = ArrayList<Article>()

        articles.add(Article("John Doe",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit",
        "Lorem ipsum text description", "4/14/2021", "Daily Times", "Lorem", "https://www.bbc.com/news/business-56736177 "))

        articles.add(Article("John Doe",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit",
        "Lorem ipsum text description", "4/14/2021", "Daily Times", "Lorem", "https://www.bbc.com/news/business-56736177 "))

        articles.add(Article("John Doe",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit",
        "Lorem ipsum text description", "4/14/2021", "Daily Times", "Lorem", "https://www.bbc.com/news/business-56736177 "))

        articles.add(Article("John Doe",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit",
        "Lorem ipsum text description", "4/14/2021", "Daily Times", "Lorem", "https://www.bbc.com/news/business-56736177 "))

        articles.add(Article("John Doe",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit",
        "Lorem ipsum text description", "4/14/2021", "Daily Times", "Lorem", "https://www.bbc.com/news/business-56736177 "))

        articles.add(Article("John Doe",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit",
        "Lorem ipsum text description", "4/14/2021", "Daily Times", "Lorem", "https://www.bbc.com/news/business-56736177 "))

        articles.add(Article("John Doe",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit",
        "Lorem ipsum text description", "4/14/2021", "Daily Times", "Lorem", "https://www.bbc.com/news/business-56736177 "))

        articles.add(Article("John Doe",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit",
        "Lorem ipsum text description", "4/14/2021", "Daily Times", "Lorem", "https://www.bbc.com/news/business-56736177 "))

        articles.add(Article("John Doe",
            "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit",
        "Lorem ipsum text description", "4/14/2021", "Daily Times", "Lorem", "https://www.bbc.com/news/business-56736177 "))


        return articles
    }
}

The MainActivity is very straight forward, just setup binding if you don't know how to do that then I suggest you check out my previous article where I explained it in a more detailed way Using View binding to replace findViewById on Android With the binding done we setup the RecyclerView, setting the adapter and also calling setOnItemClickListener which shows a toast. In the getArticles method we are manually creating our list of articles and then returning the list to be passed to the constructor of the adapter. Ideally this list would usually be gotten from a rest API or some other form of fetching data from a network but just for simplicity I created the list manually.

And so we've come to the end of this wonderful journey hope you enjoyed it as much as I did, if there is anything you did not understand or any mistake I made you can leave a comment or send me a tweet at @henry_ifechukwu Have a nice day.