Working with RecyclerView in Android

Introduction

RecyclerView is a powerful and flexible tool for displaying a large collection of data in a limited window. As a more advanced and efficient version of ListView, RecyclerView offers improved performance, better code architecture, and more customization options. This article will guide you through the process of implementing and using RecyclerView in your Android applications.

Setting Up

RecyclerView

Before you start using RecyclerView, you need to add the necessary dependencies to your project.

         
    dependencies {
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
}
    

Creating a Layout for

RecyclerView

First, create a layout file for your RecyclerView in your activity or fragment layout file.


    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:padding="16dp"
        android:clipToPadding="false"
        android:scrollbars="vertical"/>

</RelativeLayout>
    

Creating the Item

Layout

Create a layout file for individual items that will be displayed in the RecyclerView.


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

    <ImageView
        android:id="@+id/item_image"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_marginEnd="16dp"
        android:contentDescription="@string/app_name"
        android:src="@drawable/ic_launcher_background"/>

    <TextView
        android:id="@+id/item_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Item Title"
        android:textSize="16sp"/>

</LinearLayout>
    

Creating the

RecyclerView Adapter

The RecyclerView adapter binds the data to the views in the RecyclerView. Let's create a custom adapter by extending RecyclerView.Adapter.


    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private List<String> mData;
    private LayoutInflater mInflater;

    // data is passed into the constructor
    public MyAdapter(Context context, List<String> data) {
        this.mInflater = LayoutInflater.from(context);
        this.mData = data;
    }

    // inflates the row layout from xml when needed
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.item_layout, parent, false);
        return new ViewHolder(view);
    }

    // binds the data to the TextView in each row
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        String item = mData.get(position);
        holder.myTextView.setText(item);
    }

    // total number of rows
    @Override
    public int getItemCount() {
        return mData.size();
    }

    // stores and recycles views as they are scrolled off screen
    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        TextView myTextView;

        ViewHolder(View itemView) {
            super(itemView);
            myTextView = itemView.findViewById(R.id.item_text);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            // handle item click events here
        }
    }
}
    

Integrating

RecyclerView in

Activity

Now, let's integrate the RecyclerView in an activity. First, initialize the RecyclerView and set its adapter.


    public class MainActivity extends AppCompatActivity {

    RecyclerView recyclerView;
    MyAdapter adapter;
    List<String> data;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Initialize data
        data = new ArrayList<>();
        for (int i = 1; i <= 20; i++) {
            data.add("Item " + i);
        }

        // Set up the RecyclerView
        recyclerView = findViewById(R.id.recyclerView);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        adapter = new MyAdapter(this, data);
        recyclerView.setAdapter(adapter);
    }
}
    

Layout Managers

RecyclerView provides three types of layout managers to position your items: LinearLayoutManager, GridLayoutManager, and StaggeredGridLayoutManager.

LinearLayoutManager

LinearLayoutManager arranges the items in a single column or row.


    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    

GridLayoutManager

GridLayoutManager arranges the items in a grid.


    recyclerView.setLayoutManager(new GridLayoutManager(this, 2)); // 2 columns
    

StaggeredGridLayoutManager

StaggeredGridLayoutManager arranges the items in a staggered grid.

 
    recyclerView.setLayoutManager(new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)); // 2 columns
    

Handling Click Events

To handle click events on RecyclerView items, you can implement the View.OnClickListener interface in your ViewHolder.

       
    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    //... other methods

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        String item = mData.get(position);
        holder.myTextView.setText(item);
    }

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

    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        TextView myTextView;

        ViewHolder(View itemView) {
            super(itemView);
            myTextView = itemView.findViewById(R.id.item_text);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            int position = getAdapterPosition();
            if (position != RecyclerView.NO_POSITION) {
                // Handle the click event here
                String item = mData.get(position);
                Toast.makeText(view.getContext(), "Clicked: " + item, Toast.LENGTH_SHORT).show();
            }
        }
    }
}
    

Implementing DiffUtil

for Efficient Updates

DiffUtil is a utility class that helps you update RecyclerView efficiently. It calculates the difference between two lists and provides the minimal update steps for the RecyclerView adapter.


    public class MyDiffCallback extends DiffUtil.Callback {

    private final List<String> oldList;
    private final List<String> newList;

    public MyDiffCallback(List<String> oldList, List<String> newList) {
        this.oldList = oldList;
        this.newList = newList;
    }

    @Override
    public int getOldListSize() {
        return oldList.size();
    }

    @Override
    public int getNewListSize() {
        return newList.size();
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return oldList.get(oldItemPosition).equals(newList.get(newItemPosition));
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        return oldList.get(oldItemPosition).equals(newList.get(newItemPosition));
    }
}
    

Using DiffUtil in

Adapter

To use DiffUtil in your adapter, create a method to update your data list and notify the adapter of the changes.

 
    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private List<String> mData;

    //... other methods

    public void updateData(List<String> newData) {
        DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new MyDiffCallback(mData, newData));
        mData.clear();
        mData.addAll(newData);
        diffResult.dispatchUpdatesTo(this);
    }
}
    

Using Data Binding

with RecyclerView

Data binding allows you to bind UI components in your layouts to data sources in your app. This can reduce boilerplate code and improve the readability of your code.

First, enable data binding in your project by adding the following code to your build.gradle file:


    android {
    ...
    dataBinding {
        enabled = true
    }
}
    

Next, create a layout file for your RecyclerView item that uses data binding:


    <?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">

    <data>
        <variable
            name="item"
            type="java.lang.String"/>
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:padding="16dp">

        <ImageView
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_marginEnd="16dp"
            android:contentDescription="@{@string/app_name}"
            android:src="@drawable/ic_launcher_background"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{item}"
            android:textSize="16sp"/>

    </LinearLayout>

</layout>
    

Then, update your adapter to use data binding:


    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

    private List<String> mData;

    public MyAdapter(List<String> data) {
        this.mData = data;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        ItemLayoutBinding binding = DataBindingUtil.inflate(inflater, R.layout.item_layout, parent, false);
        return new ViewHolder(binding);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        String item = mData.get(position);
        holder.binding.setItem(item);
        holder.binding.executePendingBindings();
    }

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

    public static class ViewHolder extends RecyclerView.ViewHolder {
        final ItemLayoutBinding binding;

        public ViewHolder(ItemLayoutBinding binding) {
            super(binding.getRoot());
            this.binding = binding;
        }
    }
}
    

Implementing Swipe

to Delete and Drag &

Drop

RecyclerView supports swipe to delete and drag & drop functionality through the ItemTouchHelper class. This allows you to add interactive features to your RecyclerView.


    ItemTouchHelper.SimpleCallback simpleItemTouchCallback = new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        return false;
    }

    @Override
    public void onSwiped(RecyclerView.ViewHolder viewHolder, int swipeDir) {
        // Remove item from the adapter
        int position = viewHolder.getAdapterPosition();
        mData.remove(position);
        adapter.notifyItemRemoved(position);
    }
};

ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleItemTouchCallback);
itemTouchHelper.attachToRecyclerView(recyclerView);
    

Pagination with

RecyclerView

To handle large datasets efficiently, you can implement pagination in RecyclerView. This allows you to load data in chunks, improving performance and user experience.


    recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);

        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();

        if (linearLayoutManager != null && linearLayoutManager.findLastCompletelyVisibleItemPosition() == mData.size() - 1) {
            // Load more data here
        }
    }
});
    

Conclusion

RecyclerView is a highly flexible and efficient tool for displaying large datasets in Android. By following the steps outlined in this article, you can implement a RecyclerView in your application, handle item clicks, update data efficiently with DiffUtil, integrate data binding, and add interactive features like swipe to delete and pagination. With these tools, you can create a dynamic and user-friendly app experience.

Post a Comment

Previous Post Next Post