Android Kotlin: How to add and remove item from RecyclerView

Introduction

This code demonstrates how to manage a list of items in a RecyclerView using Kotlin in an Android application. The example showcases adding and removing items dynamically. A button click triggers the addition of a new item ("Donkey") to the list displayed by the RecyclerView. Clicking on the delete icon next to each item in the list removes it.

Breakdown

The code consists of three parts:

  1. MainActivity.kt: This file defines the main activity of the application. It initializes the UI components (button and RecyclerView), creates a list of animals (data source), sets up the RecyclerView layout manager (GridLayoutManager), and creates an adapter to bind the data to the RecyclerView. It also implements the logic for adding a new item to the list when the button is clicked.

  2. RecyclerViewAdapter.kt: This file defines the adapter class for the RecyclerView. It holds the data source (list of animals) and inflates a custom layout (custom_view.xml) for each item. It binds the animal name to the TextView and handles the click event on the delete icon to remove the corresponding item from the list and update the RecyclerView.

  3. XML Layouts: There are two layout files:

    • activity_main.xml: This defines the main layout of the activity containing the button and the RecyclerView.
    • custom_view.xml: This defines the layout for each item displayed in the RecyclerView. It includes a TextView to display the animal name and an ImageView representing the delete icon.

Summary

This example provides a basic understanding of how to manage a dynamic list of items in an Android application using RecyclerView and Kotlin. The code demonstrates how to add and remove items from the list, update the adapter to reflect changes, and notify the RecyclerView to refresh its view.


MainActivity.kt

package com.cfsuman.kotlintutorials

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


class MainActivity : AppCompatActivity() {
    private lateinit var context:MainActivity

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

        // Get the context
        context = this

        // Get the widgets reference from XML layout
        val button = findViewById<Button>(R.id.button)
        val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)


        // initialize a mutable list of animals
        val animals = mutableListOf(
            "Aardvark", "Albatross", "Alligator",
            "Alpaca", "Ant", "Anteater",
            "Barracuda", "Bear"
        )

        // initialize grid layout manager
        GridLayoutManager(
            context, // context
            2, // span count
            RecyclerView.VERTICAL, // orientation
            false // reverse layout
        ).apply {
            // specify the layout manager for recycler view
            recyclerView.layoutManager = this
        }

        // finally, data bind the recycler view with adapter
        val adapter = RecyclerViewAdapter(animals).apply {
            recyclerView.adapter = this
        }


        // add an item to recycler view
        button.setOnClickListener {
            it.isEnabled = false
            // add an item at the end of list
            animals.add("Donkey")
            adapter.notifyItemInserted(animals.size - 1)
            recyclerView.scrollToPosition(animals.size - 1)
        }
    }
}
RecyclerViewAdapter.kt

package com.cfsuman.kotlintutorials

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


class RecyclerViewAdapter(private val animals: MutableList<String>)
    : RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder>() {

    override fun onCreateViewHolder(
        parent: ViewGroup, viewType: Int): ViewHolder {
        // inflate the custom view from xml layout file
        val view: View = LayoutInflater.from(parent.context)
            .inflate(R.layout.custom_view,parent,false)

        // return the view holder
        return ViewHolder(view)
    }


    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        // display the current animal
        holder.animal.text = animals[position]

        // remove the item from recycler view
        holder.remove.setOnClickListener {
            animals.removeAt(position)
            notifyItemRemoved(position)
            notifyItemRangeChanged(position,animals.size)
        }
    }


    override fun getItemCount(): Int {
        // number of items in the data set held by the adapter
        return animals.size
    }


    class ViewHolder(itemView: View)
        : RecyclerView.ViewHolder(itemView){
        val animal: TextView = itemView.findViewById(R.id.tvAnimal)
        val remove: ImageView = itemView.findViewById(R.id.ivDelete)
    }


    // this two methods useful for avoiding duplicate item
    override fun getItemId(position: Int): Long {
        return position.toLong()
    }


    override fun getItemViewType(position: Int): Int {
        return position
    }
}
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    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="match_parent"
    android:id="@+id/rootLayout"
    android:background="#DCDCDC">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:text="Add Item : Donkey"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

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

</androidx.constraintlayout.widget.ConstraintLayout>
custom_view.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/cardView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardBackgroundColor="#F5F5F5"
    app:cardCornerRadius="8dp"
    app:cardElevation="4dp"
    app:cardMaxElevation="6dp"
    app:contentPadding="16dp"
    android:layout_margin="6dp" >

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:id="@+id/tvAnimal"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:fontFamily="sans-serif"
            android:textSize="20sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/ivDelete"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <ImageView
            android:id="@+id/ivDelete"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="12dp"
            android:src="@drawable/ic_action_delete"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>

</androidx.cardview.widget.CardView>
More android kotlin tutorials