Android RecyclerView Example
Recently for my app, I needed to provide a scrollable list of clickable items. After doing a little research I found that the RecyclerView is the recommended choice since it recycles view items that are not in the user's focus. Here is a sample app that I created to demonstrate how to implement such a list.
Here is what the app looks like.
Now to get into the details of how to implement this list. First, let's take a look at how the RecyclerView is setup in a layout XML file. Note: I referenced the Google example, Creating Lists and Cards, which is why the code looks very similar.
activity_main.xml
1| <?xml version="1.0" encoding="utf-8"?> 2| <LinearLayout> 3| xmlns:android="http://schemas.android.com/apk/res/android" 4| xmlns:tools="http://schemas.android.com/tools" 5| android:id="@+id/activity_main" 6| android:orientation="vertical" 7| android:layout_width="match_parent" 8| android:layout_height="match_parent" 9| android:paddingBottom="@dimen/activity_vertical_margin" 10| android:paddingLeft="@dimen/activity_horizontal_margin" 11| android:paddingRight="@dimen/activity_horizontal_margin" 12| android:paddingTop="@dimen/activity_vertical_margin" 13| tools:context="com.example.johnqualls.recyclerviewdemo.MainActivity"> 14| <Button 15| android:id="@+id/addItem" 16| android:layout_width="match_parent" 17| android:layout_height="wrap_content" 18| android:text="Add"/> 19| <Button 20| android:id="@+id/removeItem" 21| android:layout_width="match_parent" 22| android:layout_height="wrap_content" 23| android:text="Remove"/> 24| <android.support.v7.widget.RecyclerView 25| android:id="@+id/my_recycler_view" 26| android:scrollbars="vertical" 27| android:layout_width="match_parent" 28| android:layout_height="wrap_content"/> 29| </LinearLayout>
The important thing to note here is the RecyclerView element at the bottom (Line 24). This element is placed where you want your list to appear in the UI. It is also needed by the Activity (or Fragment) to programmatically retrieve a reference. Next, we'll take a look at the Activity code to see how to configure the RecyclerView.
MainActivity.java
1| package com.example.johnqualls.recyclerviewdemo; 2| 3| import android.app.Activity; 4| import android.os.Bundle; 5| import android.support.v7.widget.LinearLayoutManager; 6| import android.support.v7.widget.RecyclerView; 7| import android.view.View; 8| import android.widget.Button; 9| 10| import java.util.ArrayList; 11| import java.util.List; 12| 13| public class MainActivity extends Activity implements Button.OnClickListener{ 14| private int count; 15| private RecyclerView mRecyclerView; 16| private TestAdapter mAdapter; 17| private RecyclerView.LayoutManager mLayoutManager; 18| private List- dataset; 19| private Button addItem, 20| removeItem; 21| private boolean clickable; 22| 23| @Override 24| protected void onCreate(Bundle savedInstanceState) { 25| super.onCreate(savedInstanceState); 26| setContentView(R.layout.activity_main); 27| mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view); 28| 29| // Register buttons 30| clickable = true; 31| addItem = (Button) findViewById(R.id.addItem); 32| removeItem = (Button) findViewById(R.id.removeItem); 33| addItem.setOnClickListener(this); 34| removeItem.setOnClickListener(this); 35| 36| // use this setting to improve performance if you know that changes 37| // in content do not change the layout size of the RecyclerView 38| mRecyclerView.setHasFixedSize(true); 39| 40| // use a linear layout manager 41| mLayoutManager = new LinearLayoutManager(this); 42| mRecyclerView.setLayoutManager(mLayoutManager); 43| 44| // Initialize dataset 45| dataset = new ArrayList<>(); 46| Item item = new Item("Key0", "Value0"); 47| dataset.add(item); 48| 49| // Counter for newly added Items 50| count = 1; 51| 52| // specify an adapter 53| mAdapter = new TestAdapter(dataset); 54| mRecyclerView.setAdapter(mAdapter); 55| } 56| 57| 58| @Override 59| public void onClick(View view) { 60| if(view.getId() == R.id.addItem) { 61| Item item = new Item("Key" + count, "Value" + count); 62| dataset.add(item); 63| mAdapter.notifyItemRangeInserted(dataset.size() - 1, 1); 64| count++; 65| } 66| else if(dataset.size() > 0){ 67| int removePosition = dataset.size() - 1; 68| dataset.remove(removePosition); 69| mRecyclerView.removeViewAt(removePosition); 70| count--; 71| } 72| } 73| }
There are few steps involved when setting up the RecyclerView in the Activity.
- A RecyclerView reference must be retreieved.
- Initialize and set the RecyclerView's LinearLayoutManager. This is needed to manage the LinearLayouts used in the TestAdapter class.
- Initialize data set.
- Pass the data set reference as a constructor parameter of a newly constructed RecyclerView.Adapter type (TestAdapter used as my sub class implementation), and set it as the RecyclerView's Adapter.
- In order to notify the RecyclerView to dynamically update the View items when data set elements are changed, the following lines are needed.
27| mRecyclerView = (RecyclerView) findViewById(R.id.my_recycler_view);
40| // use a linear layout manager 41| mLayoutManager = new LinearLayoutManager(this); 42| mRecyclerView.setLayoutManager(mLayoutManager);
44| // Initialize dataset 45| dataset = new ArrayList<>(); 46| Item item = new Item("Key0", "Value0"); 47| dataset.add(item);
52| // specify an adapter 53| mAdapter = new TestAdapter(dataset); 54| mRecyclerView.setAdapter(mAdapter);
63| mAdapter.notifyItemRangeInserted(dataset.size() - 1, 1); ... 69| mRecyclerView.removeViewAt(removePosition);
TestAdapter.java
The adapter is needed to bind data set elements to View instances.
Source: Creating Lists and Cards
1| package com.example.johnqualls.recyclerviewdemo; 2| 3| import android.support.v7.widget.RecyclerView; 4| import android.util.Log; 5| import android.view.LayoutInflater; 6| import android.view.ViewGroup; 7| import android.widget.LinearLayout; 8| import android.widget.TextView; 9| 10| import java.util.List; 11| 12| public class TestAdapter extends RecyclerView.Adapter{ 13| private List - mDataset; 14| 15| // Provide a reference to the views for each data item 16| // Complex data items may need more than one view per item, and 17| // you provide access to all the views for a data item in a view holder 18| public static class ViewHolder extends RecyclerView.ViewHolder { 19| public LinearLayout mLinearLayout; 20| 21| public ViewHolder(LinearLayout v) { 22| super(v); 23| mLinearLayout = v; 24| } 25| } 26| 27| // Provide a suitable constructor (depends on the kind of dataset) 28| public TestAdapter(List
- myDataset) { 29| mDataset = myDataset; 31| } 32| 33| // Create new views (invoked by the layout manager) 34| @Override 35| public TestAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 36| // create a new view 37| LinearLayout v = (LinearLayout) LayoutInflater.from(parent.getContext()) 38| .inflate(R.layout.row_view, parent, false); 39| // set the view's size, margins, paddings and layout parameters 40| //... 41| ViewHolder vh = new ViewHolder(v); 42| return vh; 43| } 44| 45| // Replace the contents of a view (invoked by the layout manager) 46| @Override 47| public void onBindViewHolder(ViewHolder holder, int position) { 48| // - get element from your dataset at this position 49| // - replace the contents of the view with that element 50| Item item = mDataset.get(position); 51| 52| Log.i(TestAdapter.class.getName(), "onBindViewHolder() -> PopulateView"); 53| ((TextView) holder.mLinearLayout.getChildAt(0)).setText(item.getKey()); 54| ((TextView) holder.mLinearLayout.getChildAt(1)).setText(item.getValue()); 55| } 56| 57| // Return the size of your dataset (invoked by the layout manager) 58| @Override 59| public int getItemCount() { 60| return mDataset.size(); 61| } 62| 63| }
Let's look into the details of this class.
- The dataset reference is passed via a constructor argument.
- myDataset) { 29| mDataset = myDataset; 31| }
- ViewHolders are needed to store Views for each data item in the dataset. The row_view.xml layout is inflated and a reference is passed to a new ViewHolder. In this example, I'm using one LinearLayout per data item.
- onBindViewHolder() is invoked for each newly initialized ViewHolder. This is where the view is updated with the corresponding data item. In this example, I am applying two values to TextViews within a LinearLayout.
- Finally, the dataset size must be returned from getItemCount(). This is required in order for the LayoutManager to function correctly.
28| public TestAdapter(List
33| // Create new views (invoked by the layout manager) 34| @Override 35| public TestAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 36| // create a new view 37| LinearLayout v = (LinearLayout) LayoutInflater.from(parent.getContext()) 38| .inflate(R.layout.row_view, parent, false); 39| // set the view's size, margins, paddings and layout parameters 40| //... 41| ViewHolder vh = new ViewHolder(v); 42| return vh; 43| }
46| @Override 47| public void onBindViewHolder(ViewHolder holder, int position) { 48| // - get element from your dataset at this position 49| // - replace the contents of the view with that element 50| Item item = mDataset.get(position); 51| 52| Log.i(TestAdapter.class.getName(), "onBindViewHolder() -> PopulateView"); 53| ((TextView) holder.mLinearLayout.getChildAt(0)).setText(item.getKey()); 54| ((TextView) holder.mLinearLayout.getChildAt(1)).setText(item.getValue()); 55| }
58| @Override 59| public int getItemCount() { 60| return mDataset.size(); 61| }
row_view.xml
This layout represents the UI for each row in the RecyclerView list.
1| <?xml version="1.0" encoding="utf-8"?> 2| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3| android:orientation="horizontal" 4| android:layout_width="match_parent" 5| android:layout_height="match_parent"> 6| <TextView 7| android:id="@+id/name1" 8| android:layout_width="match_parent" 9| android:layout_height="wrap_content" 10| android:layout_weight=".5" 12| android:textSize="16sp"/> 13| 14| <TextView 15| android:id="@+id/name2" 16| android:layout_width="match_parent" 17| android:layout_height="wrap_content" 18| android:layout_weight=".5" 19| android:textSize="16sp"/> 20| </LinearLayout>
At this point, you should now have a fully functional RecyclerView that can remove and add items at runtime!
The source code can be downloaded from my GitHub Repository.
Comments
Post a Comment