• Monday, November 19, 2018

    Easy Android RecyclerView implementation with Adapter, Holder, Click Listener Example in Java and Kotlin both

    Art Soft
    With lot of efforts and writing huge code for Android RecyclerView, I ended up with this code, but for now I think it is very easy to use and handle click listener. This implementation is different from any other implementation you see on many sites.

    Let's begin with coding...

    Create a new project with Android Studio with empty Activity "MainActivity"
    Configure Activity - Android Studio


    First we need to create a model (create separate package for all models is good)
    Hierarchy of Android Project - Android Studio


    models/Student.java

    
    package com.masoomyf.recyclerviewexample.models;
    
    public class Student {
        private int id;
        private int age;
    
        private String name;
    
        public Student(int id, int age, String name) {
            this.id = id;
            this.age = age;
            this.name = name;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    KOTLIN
    models/Student.kt

    
    package com.masoomyf.recyclerviewexample.models;
    
    class Student(var id: Int, var age: Int, var name: String?)
    
    

    Add RecyclerView to your main_layout.xml, it will auto configure RecyclerView library for you in gradle. (Add RecyclerView in Design Tab only)

    Now create layout xml file: row_layout_student.xml 
    Layout for RecyclerView Adapter with Constraint Layout

    
    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
                                                 xmlns:app="http://schemas.android.com/apk/res-auto"
                                                 xmlns:tools="http://schemas.android.com/tools"
                                                 android:layout_width="match_parent"
                                                 android:layout_height="wrap_content">
    
        <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:id="@+id/tvStudentName" app:layout_constraintStart_toStartOf="parent"
                android:layout_marginStart="8dp"
                android:layout_marginTop="8dp" app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp" tools:text="Student Name"
                android:textStyle="bold"/>
        <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:id="@+id/tvStudentId" app:layout_constraintStart_toStartOf="parent" android:layout_marginStart="8dp"
                android:layout_marginTop="8dp" app:layout_constraintTop_toBottomOf="@+id/tvStudentName"
                tools:text="ID: 12345"
                app:layout_constraintHorizontal_bias="0.5" app:layout_constraintEnd_toStartOf="@+id/tvStudentAge"/>
        <TextView
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:id="@+id/tvStudentAge" app:layout_constraintEnd_toEndOf="parent" android:layout_marginEnd="8dp"
                android:layout_marginTop="8dp" app:layout_constraintTop_toBottomOf="@+id/tvStudentName"
                app:layout_constraintStart_toEndOf="@+id/tvStudentId" app:layout_constraintHorizontal_bias="0.5"
                tools:text="Age: 21"/>
        <View
                android:id="@+id/divider"
                android:layout_width="0dp"
                android:layout_height="1dp"
                android:background="?android:attr/listDivider"
                app:layout_constraintEnd_toEndOf="parent"
                android:layout_marginEnd="8dp" app:layout_constraintStart_toStartOf="parent"
                android:layout_marginStart="8dp" app:layout_constraintTop_toBottomOf="@+id/tvStudentAge"/>
    </android.support.constraint.ConstraintLayout>
    


    Now create Adapter for RecyclerView: 
    
    package com.masoomyf.recyclerviewexample.adapters;
    
    import android.support.annotation.NonNull;
    import android.support.v7.widget.RecyclerView;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.TextView;
    import com.masoomyf.recyclerviewexample.R;
    import com.masoomyf.recyclerviewexample.models.Student;
    
    import java.util.List;
    
    public class StudentAdapter extends RecyclerView.Adapter<StudentAdapter.StudentHolder> {
        //We don't need any context field. We can get context from viewGroup.
        private List<Student> studentList;
        private View.OnClickListener clickListener;
    
        public StudentAdapter(List<Student> studentList) {
            this.studentList = studentList;
        }
    
    
        @NonNull
        @Override
        public StudentHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
            View view = LayoutInflater.from(viewGroup.getContext())
                    .inflate(R.layout.row_layout_student,viewGroup,false);
    
            return new StudentHolder(view);
        }
    
        @Override
        public void onBindViewHolder(@NonNull StudentHolder studentHolder, int i) {
            studentHolder.bind(studentList.get(i));
        }
    
        public void setClickListener(View.OnClickListener clickListener) {
            this.clickListener = clickListener;
        }
    
        @Override
        public int getItemCount() {
            return studentList.size();
        }
    
        class StudentHolder extends RecyclerView.ViewHolder{
            private TextView tvStudentId;
            private TextView tvStudentName;
            private TextView tvStudentAge;
    
            StudentHolder(@NonNull View itemView) {
                super(itemView);
                //Setup all views inside itemView
                tvStudentId = itemView.findViewById(R.id.tvStudentId);
                tvStudentAge = itemView.findViewById(R.id.tvStudentAge);
                tvStudentName = itemView.findViewById(R.id.tvStudentName);
                //set the itemView click listener.
                itemView.setOnClickListener(clickListener);
            }
            //It's look beautiful and become easy when we create bind method inside holder.
            void bind(Student student){
                tvStudentAge.setText(String.valueOf("Age: " + student.getAge()));
                tvStudentName.setText(student.getName());
                tvStudentId.setText(String.valueOf("Id: "+student.getId()));
                //Always set tag after binding, if there is already a tag in itemView, it get replaced.
                itemView.setTag(student);
            }
        }
    }
    
    
    KOTLIN
    
    import android.support.v7.widget.RecyclerView
    import android.view.LayoutInflater
    import android.view.View
    import android.view.ViewGroup
    import com.masoomyf.recyclerviewexample.R
    import com.masoomyf.recyclerviewexample.models.Student
    import kotlinx.android.synthetic.main.row_layout_student.view.*
    
    
    class StudentAdapter(
        private val studentList: List<Student>
    ) : RecyclerView.Adapter<StudentAdapter.StudentHolder>() {
    
        var clickListener: View.OnClickListener? = null
    
        override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): StudentHolder {
            val view = LayoutInflater.from(viewGroup.context)
                .inflate(R.layout.row_layout_student, viewGroup, false)
    
            return StudentHolder(view)
        }
    
        override fun onBindViewHolder(studentHolder: StudentHolder, i: Int) = studentHolder.bind(studentList[i])
    
    
        override fun getItemCount(): Int = studentList.size
       
    
        inner class StudentHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    
            init {
                itemView.setOnClickListener(clickListener)
            }
    
            //It's look beautiful and become easy when we create bind method inside holder.
            fun bind(student: Student) {
                with(itemView) {
                    tvStudentAge.text = "Age: %d".format(student.age)
                    tvStudentName.text = student.name
                    tvStudentId.text = "Id: %d".format(student.id)
                    //Always set tag after binding, if there is already a tag in itemView, it get replaced.
                    tag = student
                }
            }
        }
    }
    
    
    Add code in MainActivity.java to complete RecyclerView
    
    
    package com.masoomyf.recyclerviewexample;
    
    import android.os.Bundle;
    import android.support.annotation.Nullable;
    import android.support.v7.app.AppCompatActivity;
    import android.support.v7.widget.LinearLayoutManager;
    import android.support.v7.widget.RecyclerView;
    import android.view.View;
    import android.widget.Toast;
    import com.masoomyf.recyclerviewexample.adapters.StudentAdapter;
    import com.masoomyf.recyclerviewexample.models.Student;
    
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
        //Recycler view instance holder.
        
        private RecyclerView rvStudent;
        private List<Student> studentList;
    
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            setupObject();
            setupUI();
        }
        //It's good to setup all object in seperate method
        private void setupObject() {
            studentList = new ArrayList<>();
        }
        
        //This method will setup the whole UI, it's better to setup UI in seperate method.
        private void setupUI() {
            rvStudent = findViewById(R.id.rvStudent);
            //We don't need to declare adapter variable in field.
            // We can get adapter through recycler view whenever we need.
            StudentAdapter adapter = new StudentAdapter(studentList);
            adapter.setClickListener(studentListClickListener);
            generateDummyData();
            rvStudent.setLayoutManager(new LinearLayoutManager(this));
            rvStudent.setAdapter(adapter);
    
        }
        //Add some dummy data to list.
        private void generateDummyData() {
            studentList.add(new Student(1,19,"Yash"));
            studentList.add(new Student(2,21,"Masoom"));
            studentList.add(new Student(3,22,"Yashika"));
            studentList.add(new Student(4,24,"Amiy"));
        }
        //A click listener object that will fire when itemView get clicked with current item tag
        private View.OnClickListener studentListClickListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //Get the Student object from itemView tag.
                Student student = (Student) v.getTag();
                Toast.makeText(MainActivity.this,student.getName(), Toast.LENGTH_SHORT).show();
            }
        };
    }
    
    
    
    KOTLIN
    
    
    package com.masoomyf.recyclerviewexample
    
    import android.support.v7.app.AppCompatActivity
    import android.os.Bundle
    import android.support.v7.widget.LinearLayoutManager
    import android.view.View
    import android.widget.Toast
    import com.masoomyf.recyclerviewexample.adapters.StudentAdapter
    import com.masoomyf.recyclerviewexample.models.Student
    import kotlinx.android.synthetic.main.activity_main.*
    
    
    
    class MainActivity : AppCompatActivity() {
    
        private val studentList = arrayListOf<Student>()
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            setupUI()
        }
    
        private fun setupUI() {
            val studentAdapter = StudentAdapter(studentList).apply {
                clickListener = studentClickListener
            }
    
            generateDummyData()
    
            with(rvStudent){
                layoutManager = LinearLayoutManager([email protected])
                adapter = studentAdapter
            }
        }
    
        private fun generateDummyData() {
            with(studentList) {
                add(Student(1, 19, "Yash"))
                add(Student(2, 21, "Masoom"))
                add(Student(3, 22, "Yashika"))
                add(Student(4, 24, "Amiy"))
            }
        }
    
    
        private val studentClickListener = View.OnClickListener {
            val student = it.tag as Student
            Toast.makeText(this,"Student Name: ${student.name}",Toast.LENGTH_LONG).show()
        }
    }