Working with RecyclerView in Android

Overview

In Android 5.0 Lollipop, Android introduced RecyclerView widget. Android RecyclerView is more advanced version of ListView/ GridView with improved performance and other benefits. Using RecyclerView and CardView both lists and grids can be created very easily. It is a modernized version of ListView and GridView provided by Android.

The RecyclerView class supports the display of a collection of data. It provides extra features that make more maintainable code and enforce memory efficient design.


Why RecyclerView

In a typical ListView you create a custom row layout with some complex layout design and inflate that layout in getView() method of List Adapter. After then you get the views, add some logic and pass that view to the ListView. So ListViews and GridViews achieve some memory efficiency like-

     @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        convertView = mInflater.inflate(R.layout.list_item, null);
        TextView txtTitle = (TextView) convertView.findViewById(R.id.title);
        ImageView imageView = (ImageView) convertView.findViewById(R.id.icon);
        txtTitle.setText("");
        imageView.setImageResource(getImageId());
        return convertView;
    }          

ListView and GridView recycle the item layout (ex. R.layout.list_item), but don’t keep references to the layout children (ex. R.id.title, R.id.icon). It force you to call findViewById() for every child of your item layout every time you call getView(). This makes ListView/GridView scrolling becomes jerky or non-responsive.

To resolve this problem Android initially provided a solution via View Holder pattern.
When you use this pattern, you create a class that becomes an in-memory reference to all the views needed to fill your layout. The benefit is you set the references once and reuse them, effectively working around the performance hit that comes with repeatedly calling findViewById().

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null;
         LayoutInflater mInflater = (LayoutInflater) context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.list_item, null);
            holder = new ViewHolder();
            holder.txtTitle = (TextView) convertView.findViewById(R.id.title);
            holder.imageView = (ImageView) convertView.findViewById(R.id.icon);
            convertView.setTag(holder);
        } else
            holder = (ViewHolder) convertView.getTag();
                
        holder.txtTitle.setText("");
        holder.imageView.setImageResource(getImageId());
        return convertView;
    }

More on the ViewHolder pattern can be found here –


How recyclerView works and its benefit

As explained above ViewHolder is an optional pattern for ListView or GridView. If forget to implement the ViewHolder pattern in your ListView or GridView then scrolling will result non responsive.

Recycler view uses ViewHolder to store references of views and recycling the views. So you do not worry to handle it explicitly. It also comes with default animation. You can even create your own animations and apply them as needed.

RecyclerView introduces an additional level of abstraction between the RecyclerView.Adapter and RecyclerView.LayoutManager to be able to detect data set changes in batches during a layout calculation. This saves LayoutManager from tracking adapter changes to calculate animations. It also helps with performance because all view bindings happen at the same time and unnecessary bindings are avoided.

For this reason, there are two types of position related methods in RecyclerView:

layout position: Position of an item in the latest layout calculation. This is the position from the LayoutManager's perspective.

adapter position: Position of an item in the adapter. This is the position from the Adapter's perspective.


Using RecylerView

In this exercise you create a project which uses the RecyclerView class to display a list.

Add the Gradle dependency
Add the following dependency to your Gradle build file to use RecylerView.

dependencies 
    compile 'com.android.support:recyclerview-v7:25.1.0
}


Create Activity Layout

Create a new file activity_main.xml and recyclerview_item.xml inside layout resource folder and paste the following snippets.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="match_parent"
   
app:layout_behavior="@string/appbar_scrolling_view_behavior"
   
tools:context="com.androidjavapoint.recyclerviewexample.MainActivity"
   
tools:showIn="@layout/activity_main">

    <
android.support.v7.widget.RecyclerView
       
android:id="@+id/recyclerView"
       
android:layout_width="match_parent"
       
android:layout_height="wrap_content"
       
android:scrollbars="vertical" />

</
RelativeLayout>

recyclerview_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content
    android:layout_margin="10dp
    android:orientation="vertical">

    <TextView

        android:id="@+id/employeeName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="18dp"
        android:textStyle="bold" />

    <TextView
        android:id="@+id/employeeId"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
       android:textSize="14dp" />
</LinearLayout>


The MainActivity.java class is defined below :

package com.androidjavapoint.recyclerviewexample;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);


        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);


        recyclerView.setHasFixedSize(true);

        LinearLayoutManager llm = new LinearLayoutManager(this);

        llm.setOrientation(LinearLayoutManager.VERTICAL);

        recyclerView.setLayoutManager(llm);



        List<Employee> employeeList = prepareEmployeeList();

        EmployeeListAdapter ca = new EmployeeListAdapter(employeeList);

        recyclerView.setAdapter(ca);

    }


    private List<Employee> prepareEmployeeList() {

        List<Employee> employeeList = new ArrayList<>();

        for (int i = 1; i < 20; i++) {

            employeeList.add(new Employee("Employee " + i, i * 1000));
        }

        return employeeList;
    }

}


The EmployeeListAdapter.java class is defined below:

package com.androidjavapoint.recyclerviewexample;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import java.util.List;

class EmployeeListAdapter extends RecyclerView.Adapter<EmployeeListAdapter.CustomViewHolder> {
    private List<Employee> mEmployeeList;

    EmployeeListAdapter(List<Employee> mEmployeeList) {
        this.mEmployeeList = mEmployeeList;
    }

    class CustomViewHolder extends RecyclerView.ViewHolder {

        TextView employeeName;

        TextView employeeId;

        CustomViewHolder(View view) {
            super(view);
            employeeName = (TextView) view.findViewById(R.id.employeeName);
            employeeId = (TextView) view.findViewById(R.id.employeeId);
        }
    }

    @Override
    public void onBindViewHolder(CustomViewHolder holder, int position) {

        Employee employee = mEmployeeList.get(position);

        holder.employeeName.setText(employee.getEmployeeName());

        holder.employeeId.setText(String.valueOf(employee.getEmployeeId()));
    }


    @Override
   public int getItemCount() {
        return mEmployeeList.size();
    }

   @Override
    public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recyclerview_item, parent, false);

        return new CustomViewHolder(view);
    }

}


The Employee.java class which contains the data specific to this application are given below :

package com.androidjavapoint.recyclerviewexample;

public class Employee {

    private String employeeName;

    private int employeeId;

    public Employee(String employeeName, int employeeId) {

        this.employeeName = employeeName;

        this.employeeId = employeeId;
    }


    public String getEmployeeName() {

        return employeeName;
    }


    public int getEmployeeId() {

        return employeeId;
    }

}

At the end of this post I hope you gained the knowledge about Android RecyclerView.

To find more interesting topics on Software development follow me at https://medium.com/@ankit.sinhal

You can also find my Android Applications on play store





Comments

Popular posts from this blog

Android Performance: Avoid using ENUM on Android

Android O: Impact On Running Apps And Developer Viewpoint

Smart way to update RecyclerView using DiffUtil