• Meghan Gill

RecyclerView in Android

Updated: Sep 18, 2021


A RecyclerView holds a dynamic list (i.e. a list where things can be added or removed such as an ArrayList). The recyclerView can be either vertical or horizontal. It is an improvement on ListView in some key ways:


RecyclerView:

  1. Reuses cells while scrolling up/down - this is possible with implementing View Holder in the ListView adapter, but it was an optional thing, while in the RecycleView it's the default way of writing the adapter.

  2. Decouples list from its container - so you can put list items easily at run time in the different containers (linearLayout, gridLayout) with setting the LayoutManager.

  3. Animates common list actions - Animations are decoupled and delegated to ItemAnimator.



RecyclerView with a single TextView, with a horizontal LinearLayoutManager:


A RecyclerView can hold a single TextView, for example a list of titles.



In your activity or fragment set the LinearLayoutManager to horizontal:

//create and set the layoutManager
LinearLayoutManager horizontalLayoutManager = new LinearLayoutManager(getActivity(), 
        LinearLayoutManager.HORIZONTAL, false);
horizontalRecyclerView.setLayoutManager(horizontalLayoutManager);


RecyclerView with a group of views: ImageView and a TextView, LinearLayoutManager with default settings(vertical):


Alternatively, it can hold a group of views that are repeated.



In your activity or fragment use the default LinearLayoutManager:


LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);


Requirements for RecyclerView:

  1. The XML file for the activity or fragment needs to include the RecyclerView widget.

  2. Create a new XML dedicated to the view(s) that will be repeated by the RecyclerView.

  3. Create a custom adapter that extends RecyclerView.Adapter.

  4. Either create a subclass for a ViewHolder or create a separate class. Your custom ViewHolder needs to extend RecyclerView.ViewHolder.

  5. An activity or fragment to contain the logic (i.e. a place to set the adapter and layout manager).


XML with RecyclerView Widget


The default XML file for ListFragment, fragment_list.xml contains the RecyclerView widget:




XML for the RecyclerView Row


Create an XML layout for the row (i.e. list item) that RecyclerView will repeat. This file is called list_item.xml. It is inflated by the adapter, ListAdapter. It has an ImageView with a recipe picture to the left and a textView to the right, which contains a recipe title.




Creating a Custom RecyclerView Adapter


When creating your adapter for RecyclerView it must always extend RecyclerView.Adapter. In the example below I am also using generics to pass my custom ViewHolder, ListViewHolder. It is important that I pass the specific ViewHolder class I will be using because onCreateViewHolder() and onBindViewHolder() need to use ListViewHolder. Alternatively you could cast the ListViewHolder class if you prefer.



Variables in the Adapter


If you need any variables such as ArrayList<String> or an instance of a model class you can pass them as global variables to the ListAdapter class. You may need the variables to populate views.


Here I have passed an interface, mListener, as a global variable. It is used in the onClick() method in my ViewHolder subclass, ListViewHolder.


When do we need a Context variable? 

A variable of type Context is necessary if your adapter needs to access the Resource folder, for example if it accesses String Resources or Color Resources. 
  

Override Methods


public ListAdapter.ListViewHolder onCreateViewHolder()

This method is called as soon as the adapter is created. It is used to initialize your ViewHolder(s). It must be overridden so it returns the customized ViewHolder I created to hold each list item in my recyclerView. Therefore, the method returns a ListViewHolder.


onCreateViewHolder() takes two parameters: a) ViewGroup parent and b) int viewType.


ViewGroup parent is important for inflating a view. The parent can be one of two things:


1) the ViewGroup where the ViewHolder's list item will be placed once inflated. This is true if the view is attached to another root view (i.e. if we are adding it to another layout that's already inflated)


View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_horizontal_topics, parent, true);

or


2) if upon inflation the view is not attached to the root view ViewGroup parent: the parent parameter becomes the layout xml we are inflating. The third parameter of inflate() - attach to root is false, so the xml will be displayed in its own right.


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

The int viewType is from the getItemViewType(). When getItemViewType() is not used(i.e there is only one XML layout used in the recyclerView), int viewType always returns 0.



@NonNull
@Override 
public ListAdapter.ListViewHolder onCreateViewHolder(@NonNull ViewGroup parent,                                                                            
                    int viewType) {
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_horizontal_topics, parent, false);
    return new ListViewHolder(view);
}

 

LayoutInflater Usage


When instantiating a layout XML, the LayoutInflater class must be used. It creates the individual views in the XML. In order to use the LayoutInflater it needs access to context.


To access context:

  • On a View such as a TextView, use textView.getContext(). This will give the context of the activity in which the view is currently hosted.

  • In a fragment call getActivity().

  • In an activity you can use this because Activity is subclass of Context.

  • When in an onClickListener, or where you don't have direct access to the activity, reference the Activity name like MainActivity.this

In the onCreateViewHolder() method in order to instantiate the view for the ViewHolder we need to first instantiate the LayoutInflater and getContext for the parent view. Then the inflate() method can be called with the three parameters explained earlier (XML resource ID, ViewGroup parent, attachToRoot: true/false).



 

Once you've instantiated the view return the customized ViewHolder with the view as its parameter.



View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.recycler_horizontal_topics, parent, false);
    return new ListViewHolder(view);


public void onBindViewHolder()


public int getItemCount


getItemViewType() used when there is more than viewType. That means there are different XML files for different rows. For example if your recyclerView shows different layouts like when there is a header with one XML and content with another XML.


getViewTypeCount()


Creating a ViewHolder Inner Class


A ViewHolder is more than an object that holds the item's views. It is also the object that represents each item in our collection and will be used to display the view(s).


 

Why make the ViewHolder an inner class?


An inner class is a type of nested class. As opposed to a static nested class, an inner class is non-static. That means an inner class has access to all members of the enclosing class (including private members).


ListViewHolder is an inner class, so it is a nested class inside of the adapter. Creating a class within a class provides encapsulation. It is a succinct way to group elements that are only going to be used in one place. It makes the code more organized and readable.

 

When creating a customized ViewHolder it must always extend the base class RecyclerView.ViewHolder. Here ListViewHolder also implements View.OnClickListener.


I am implementing the OnClickListener because I want a user to be able to touch an item in the RecyclerView to select a recipe. We receive the index of the recipe chosen.



Variables in the ViewHolder


There should be a variable for each view in the RecyclerView. This RecyclerView has a variable of type TextView and ImageView. In addition, it has an int variable used to access the index of the recipe chosen when an item in the RecyclerView is clicked.



Fragment Source Code with RecyclerView Logic




That's all we need to implement a RecyclerView. The interface is useful, but optional.




42 views0 comments

Recent Posts

See All