Android ListViews Reinvented

I learned something new last week that I felt I probably should have learned a long time ago.  As I know from my previous experience in Android development, ListViews only scroll vertically.  In the past, there was no out of the box support for horizontal ListViews in Android.  Developers had to create them manually or use 3rd party libraries hosted on GitHub.  If you examined a 3rd parties source code, you would see implementing a horizontal ListView is not an easy task.  With the release of Android 4.4 KitKat (API Level 19), a new control was added to the Android SDK.  This new control is called a RecyclerView, and is available via the Android Support Library v7.

android-training

Luckily for us Xamarin Developers, we have out of the box binding to this library, so we can use this just like native Java developers.  In this post I’m going to show you how to implement a vertical ListView (just like a standard ListView), as well as a Horizontal ListView.  But we are not going to use the old legacy ListView control or a 3rd party library.  We are going to use the now out of the box RecyclerView to implement both.  The good news is that the since this is available in the Android Support Library v7, this control can run on devices from the current version of Android, all the way down to API Level 7 (Android 2.1 Eclair).  So this control remains backwards compatible with almost any device out there.  So let’s get coding!

What is a RecyclerView?

First thing’s first.  What is a RecyclerView?  When I was looking for a modern implementation for a Horizontal ListView, I found it difficult to find one that met my client’s requirements.  The majority had abandoned their projects on GitHub without explanation, so their code was somewhat outdated.  But during my research I came across this little nugget.  Even the native Java developers are starting to abandon their own custom libraries for ListViews in favor for something called a RecyclerView.  The name does not make it obvious on what it does, so I did some more research.  I come to find out that a RecyclerView is a really neat, and memory efficient, way to display large data sets in Android.  You can display them Linearly, or in a Grid.  It also supports the Adapter pattern, just like regular ListViews.

Unlike ListViews,  RecyclerViews require use of the ViewHolder Pattern for memory efficiency.  I’m not going to go into great detail on how a RecyclerView works.  Xamarin has some really good documentation on how a  RecyclerView works.  So I highly recommend you read the Xamarin documentation before proceeding, especially if you have not used the ViewHolder Pattern in the past with ListViews.  But in summary, RecyclerViews are the official replacement for ListViews.  I admit I’m so late in the game in realizing this, but now it’s time to move on!

Android Project Requirements For RecyclerView

As I said previously, the RecyclerView can run on devices from Android 2.1 (Eclair) and above.  However, there are some compile time requirements you need need to be aware of as a Developer.  First you need to download the Android Support Library SDK using the Android SDK Manager.  You will need at least Revision 21.  If you don’t have revision 21, you need to update to the latest revision available for download.

Android Support Library

Revision 21 at a minimum is required. Download the latest revision.

Second, you’ll need to add a Nuget package called “Xamarin Support Library v7 RecyclerView”.  This is the Xamarin C# bindings that allows you to access the RecyclerView in the Android Support Library v7.

RecyclerView Nuget Package

Add this Nuget Package to your project.

Implementing a RecyclerView

Now that we have the necessary libraries for using a RecyclerView, we can start implementing vertical and horizontal ListView functionality.  As you’ve probably read from the Xamarin documentation above, there are a few classes we need to implement.  I’ll admit, implementing a RecyclerView is a little bit more complex than a ListView, but it’s not that much.  You only have to implement one extra class, and add an EventHandler for ItemClick events, but it’s not that much code.  Trust me, the flexibility you gain from replacing ListView with RecyclerViews is well worth the very little extra work you have to do.

So here are the steps you need to do in order to incorporate a RecyclerView.  They are very similar to implementing an old legacy ListView, but with one extra strep.  So let’s do everything step by step for completeness.

Step 1:  Create your cell item XML Layout(s)

The first step is to create your XML Layout(s)  for each individual cell item of your RecyclerView.  In this example app, I’m going to create a Star Trek crew manifest application (**Nerd Alert!!**).  The application will show a list of Starfleet crew members in a vertical scrolling list when the device is in Portrait, and horizontally when the device is in Landscape.  This is a simple application that will not use any 3rd party libraries or tricks.  All of these things are now standard to the Android SDK. Also note that Layouts can be just about anything you can design.  This is just a simple example layout.  Here’s the layout for the Portrait orientation for each individual crew member item.

The resulting XML layout should look something like this:

Screen Shot 2015-04-10 at 10.47.14 PM

The next thing we need to do is is create what the layout will look like when we turn our device horizontally.  The XML layout will look something like below.  It is very similar to our vertical view, but with some slight differences.

The landscape layout should look like this:

Screen Shot 2015-04-10 at 10.54.57 PM

Step 2: Create your RecyclerView XML Layout

If you have implemented ListViews in the past, this step is very similar.   Instead of using the <ListView> tag, you need to use the <android.support.v7.widget.RecyclerView> tag.  Below is the code I use to define our RecyclerView layout.  In this sample, this is my Main Activity Layout (Main.axml).

Step 3: Create your ViewHolder for  Your Cell Item Layout.

So far, the first two steps are the same as if we were implementing a legacy ListView.  Step 3 here is an additional step we need to take in order to implement a RecyclerView. We need to create our ViewHolder for each individual Cell (Row) item.  However, this step was purely optional for ListViews, but highly encouraged since it improves performance and memory management when scrolling through ListViews with large data sets.  But if the ViewHolder pattern is not new to you, than this step is just like implementing it for a ListView.  Again, if you are not familiar with the ViewHolder Pattern, I suggest you read Xamarin’s blog post about it.

There’s a few things to note here.  First, our ViewHolder class needs to inherit from RecyclerView.ViewHolder.  This is defined in the Android Support Library v7.  Second, (and this is where the extra works comes into play) we need to implement a constructor that accepts two parameters.  The first parameter is the item View that is being displayed.  The second is an Action, also known as an Event Handler, that will fire when our itemView is clicked on.  This is the same as wiring the ListView.ItemClick event handler in legacy ListViews.  In this case, our ViewHolder needs to know about any clicks (taps) that may happen.

Step 4:  Create Our Adapter For The RecyclerView

The RecyclerView control, just like a ListView, follows the adapter pattern, so we need to create an Adapter for it.  Here is an example of our Adapter for our RecyclerView.

There are a few things to note here.  First, our Adapter needs to inherit from RecyclerView.Adapter.  This is just like inheriting from BaseAdapter<T> when implementing a legacy ListView.  Second, we need to override the following methods:

  • int ItemCount
  • RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
  • void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)

The ItemCount property is the equivalent of overriding the Count property on a legacy ListView Adapter.  It returns the number of items that our RecyclerView will display.

The OnCreateViewHolder() method is new, if you are familiar with legacy ListViews.  This is used to inflate our ItemView layout (CrewMemberItem.axml), create an instance of our ViewHolder, and then caches our  inflated ItemView to your ViewHolder.  This allows Android to recycle our inflated ViewItem for any future list items that will be shown on our device screen.

The OnBindViewHolder() method is the equivalent of the GetView() method on a legacy ListView Adapter.  Well, sort of.  In ListViews Adapters, the GetView was responsible for inflating your ItemView, and then binding our source data to the view.  But with OnBindViewHolder() this is not the case.  We don’t inflate any Views here.  Instead, a ViewHolder is passed in as a parameter.  Remember, that the ViewHolder has already been created, and it is now ready for us to use.  In this method, we take our ViewHolder, and then populate it with data from our current list item (position in our data source).

Lastly, we need to do some extra work here.  Unlike legacy ListView Adapters, RecyclerView.Adapters do not support “OnClick” (when the user taps on an item) events.  This is a pretty big bummer, but it’s not that much work to add on to our Adapter.  If you notice on Line 14 in the code above, I’ve created an EventHandler<int> that will allow your Activities to wire an event handler to handle “OnClick” events.  In addition, the OnClick() method (lines 63-68) will fire an event handlers that are wired to our event.  This is only a few extra lines of code, but it’s a real bummer that this isn’t built into the SDK out of the box.

Step 5: Assign a Layout Manager And Adapter to the RecyclerView

This is the final step.  In our Main Activity (or any activity), we create an instance of our RecyclerView adapter.  We then assign our adapter to our RecyclerView.  This is just like working with ListViews.  But we need to do one more thing before Android can display our RecyclerView.  And this is where I jumped out of my chair and yelled “This is freaking awesome!”   But first, here is the code for our Main Activity that creates inflates our RecyclerView.

The first thing we need to do is create an instance of a RecyclerView.LayoutManager (lines 30-32).  A LayoutManger tells Android how to display our items for our RecyclerView.  In this case, we want to the equivalent functionally of a legacy ListView.  We create the layout manager like this:

new LinearLayoutManager(this, LinearLayoutManager.Vertical, false);

The LinearLayoutManager tells Android that our data should be displayed in a list.  The second parameter of the constructor tells the Android OS that we want our list to scroll vertically.  And if we wanted to display our list Horizontally, we just pass in the LinearLayoutManager.Horizontal constant as a parameter!  It’s that easy! No third party libraries are needed and this is now part of the Android SDK! So, on lines 30-32, I say if the device is in Portrait, then show a vertical list, else show the list horizontally.  So the final output should look like this.

RecyclerView-LinearLayout-Vertical

Vertical Linear RecyclerView in Portrait

RecylerView-LInearLayout-Horizontal

Horizontal RecyclerView in Landscape

But There’s More!

Now that I’ve shown you how to replace your existing ListViews with the new RecyclerView, a RecyclerView also has other LayoutMangers.  Another cool one is to use a GridLayoutManger.  Comment out the code that assigns the LinearLayoutManager, and then uncomment the code that creates a GridLayoutManager instead (Line 36).  Now the RecyclerView displays a Grid that scrolls Horizontally (or Vertically if you choose).  So now with one class, we can create a Vertical/Horizontal linear list or create a Vertical/Horizontal GridView with just one class: the RecyclerView.  It’s about freaking time!

Full Source Code

You can download the full source code to my sample application on GitHub.  Fell free to look at the source code and learn the details of this awesome new (to me) control.  I can tell you that from now on, I’ll be using RecyclerViews instead of ListViews.  Feel free to try different layout managers and experiment.

https://github.com/SharpMobileCode/ListViewsReinvented

Summary

In this article, I explained how to use the new RecyclerView to display a list of data in a horizontal or vertical fashion.  The RecyclerView now replaces the legacy ListView, as the ListView only supported a linear vertical display.  Implementing a RecyclerView is not that much different then implementing a ListView.  There are only just a few extra things we need to implement, such as the ViewHolder, and the “OnClick” events, but the very little extra work is a small price to pay for the flexibility and awesomeness the RecyclerView provides.  I hope you learned something new, as I did.  Download my sample application from GitHub and code away!  And please feel free to leave a comment with any feedback you have!