Android Developing Tips: Using RecyclerView as Adapter-based View

Standard

As android engineer, we must already used ListView a lot if we want to show multiple items that has same template.

But there are some problems that can’t be solved by only using ListView:
1. Normally, we can only handle whole item click.
2. It’s hard to use different layout in ListView item without using ViewHolder pattern.
3. It’s become harder to handle some action within the item layout because of reason 1.

But that’s the reason why RecyclerView comes.

By default, RecyclerView is a more advanced and flexible version of ListView.
This widget is a container for displaying large data sets that can be scrolled very efficiently by maintaining a limited number of views. Use the RecyclerView widget when you have data collections whose elements change at runtime based on user action or network events.
Source: https://developer.android.com/training/material/lists-cards.html

Layout Manager

RecyclerView provides LayoutManager that can simplifies the display model of the items. RecyclerView has several built-in LayoutManager.
1. LinearLayoutManager → shows item in linear layout (can be horizontally or vertically oriented).
2. GridLayoutManager → shows item in grid (like in the grid view).
3. StaggeredGridLayoutManager→ shows item in staggered grid.

Or we can extends these LayoutManager class to create custom layout manager.

Adapter and ViewHolder Pattern

Like ListView, RecyclerView also uses adapter to handle data binding to each item. But RecyclerView by default using ViewHolder pattern to inflate the view.

First, we have to define a ViewHolder class that’s extended from RecyclerView.ViewHolder.

For example:

class CustomViewHolder extends RecyclerView.ViewHolder {
    //We have to declare any widget that we have to use to binding the data here
    TextView title;
    ImageView image;//Default constructor
    public CustomViewHolder (View itemView){
        super(itemView);
        //Then, we have to define these widgets.
        title = (TextView) itemView.findViewById(R.id.textView_title);
        image = (ImageView) itemView.findViewById(R.id.imageView_image);
    }
}

This class will be used in adapter as the view holder of the correlated item.
Example of the adapter class.

public class CustomAdapter extends RecyclerView.Adapter {
    //Method that override ViewHolder creation
    @Override
    public CustomViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View itemView = LayoutInflater.from(parent.getContext()).
        inflate(R.layout.custom_item, parent, false);
        return new CustomViewHolder(itemView);
    }
    @Override
    public void onBindViewHolder(CustomViewHolder holder, int position) {
        //Bind the data to the view here
        //For example
        //holder.title.setText(...data...);
        //holder.image.setImageResource(...data...);
    }
    @Override
    public int getItemCount() {
        //Return amount of the item that will be shown
        return 0;
    }
}

Multiple View Holder in an Adapter

Sometimes we have to handle some list with some different layouts for some different data types.
For example:
Data type A → Layout Type A
Data type B → Layout Type B
Yes, we can handle that easily with the use of Adapter and ViewHolder pattern.

First we have to define some item types in the adapter.

@Override
public int getItemViewType(int position) {
    Object object = mItems.get(position);
    if (object instanceof DataTypeA) {
        return 1;
    } else if (object instanceof DataTypeB) {
        return 2;
    } else return 0;
}

Then in the adapter class we extends class using general Recycler.ViewHolder and define different view holder in onCreateViewHolder method.

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view;
    LayoutInflater inflater = LayoutInflater.from(parent.getContext());
    switch (viewType) {
        case 1:
            view = inflater.inflate(R.layout.item_a, parent, false);
            return new ViewHolderA(view);
        case 2:
            view = inflater.inflate(R.layout.item_b, parent, false);
            return new ViewHolderB(view);
    }
    return null;
}

And finally we have to handle data binding differently for each item type.

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
    if(holder instanceOf ViewHolderA) {
        //Bind data type A here
    } else if (holder instanceOf ViewHolderB) {
        //Bind data type B here
    }
}

Leave a Reply