Well, I think using them for selection is not the right way to go. Instead, I think that you should stick with StateListDrawables and the activated state.

The use case of the sample

In this sample the user can select multiple items that are shown in purple. The first item gets selected using a long click. Any subsequent click will select or deselect items. Users can also deselect items, that were previously selected, with a single click. The user can then use a bulk delete operation on all selected items. The user should be able to see the number of currently selected items.

Obviously that sounds a lot like a contextual action bar (CAB), which is what I used. BTW: As you can see in the screenshot, the CAB doesn’t look like I expected it to look. It should use my android:colorPrimaryDark for the contextual app bar (Material lingo). But either the theming guide for material design is not correct, or maybe it’s the current L preview, or – more likely – it’s my code. Any takers? Please let me know, if you know what’s wrong here. Thanks!

Here’s a screenshot of the final result. You can also find a video near the end of this post.

RecyclerView with Contextual ActionBar and selected items

Overview

The solution that I suggest is Adapter-based. As you might recall from my last post, RecyclerView doesn’t care about the visual representation of individual items. Thus I quickly ruled out to subclass RecyclerView.

RecyclerView doesn’t itself need to know about the set of items nor about the state these items are in. In this way my proposed solution differs from the way you did selections with ListView or GridView in the past. There you checked items directly using the setItemChecked() method and you set the kind of selection mode with setChoiceMode().

With RecyclerView any information about the data set belongs to your RecyclerView.Adapter subclass. Thus anything required to show the selection state of items should also be in your RecyclerView.Adapter subclass.

The adapter not only stores information about the state of each item, but it also creates the views for each items. That’s why I use the adapter for setting the activated state.

Methods for setting the selected state

Based on this use case, I chose to add the following methods to my RecyclerView.Adapter subclass:

void toggleSelection(int pos)

void clearSelections()

int getSelectedItemCount()

List&lt;Integer&gt; getSelectedItems()

With toggleSelection() an item changes its selection state. If it was previously selected it gets deselected, and vice versa.

You can always clear all selections with clearSelections(). You shouldn’t forget to do that when you finish the action mode.

The other methods get the number of currently selected items and all positions of the currently selected items.

Notice how I used notifyDataSetChanged() and notifyItemChanged(). That’s necessary because I do not have access to the View object itself and thus cannot set the activated state directly. Instead I have to tell Android to ask the Adapter for a new ViewHolder binding.

How to use those methods from within the Activity

If you have used ListViews with the Contextual ActionBar in the past, you know that for selecting multiple items you had to set the choice mode to CHOICE_MODE_MULTIPLE_MODAL and implement the AbsListview.MultiChoiceModeListener interface to achieve the desired result. See this guide on Android’s developer site for more details. Now since RecyclerView doesn’t offer this interface (and rightly so), you have to find a way around this.

My solution is to use the GestureDetector to detect long presses. You can find this code at the end of the Activity. In the long-press callback, I create the actionmode, detect which view was pressed and call toggleSelection() on the adapter.

To understand of how selections work only two of this interface’s methods are interesting:

onActionItemClicked()

Android calls this method when the user presses the delete icon. In this method I get the list of selected items from the adapter and call the removeData() method of the adapter for each item – so that Android can smoothly animate them – as shown in the previous post. And, of course, I have to finish the action mode afterwards.

onDestroyActionMode()

Android calls this method when it’s leaving actionmode prior to showing the normal ActionBar (app bar) again. This happens either when the user selects the check mark or when he/she selects the delete icon.

The StateListDrawable XML file

So far I have shown you how to select items and set the activated state. To finally highlight those items I use StateListDrawables.

A StateListDrawable is a drawable that changes its content based on the state of the view. You can define those in XML files. The first matching entry for a given state determines which drawable Android uses. Since I only care about the activated state the XML file is actually very simple:

A short video showing the Contextual ActionBar and the selection of items

Sample project

You can download the sample from my github page. I have tagged the revision of last week’s post with “simpleSample” while the revision for this week uses the tag “selectionSample”.

Feel free to submit pull requests if you have suggestions on how to improve the code.

And that’s it for today

This was a short example of how to make use of the RecyclerView.Adapter and how to benefit from those abstractions. I guess I won’t go into much more detail about the adapter in future posts. But I recommend that you take a look at Gabriele Mariotti’s great example of how to use an RecyclerView.Adapter with sectioned lists.

I hope this post helps you in your work with RecyclerView.Adapters. Selection is just one of the many things an adapter is useful for. If you have a look at Gabriele’s gist, you can see how to use your adapter to support different view types. Just keep in mind the separation of concerns and don’t mix responsibilities.

Wolfram Rittmeyer lives in Germany and has been developing with Java for many years.

In recent years he shifted his attention to Android and blogs about anything interesting that came up while developing for Android.

Somehow if I longpress anywhere it is considered to be an element. For example if my list is empty and I make a longpress the empty list acts as it is selectable. Furthermore selected items don’t change style when selected, but I think this and the first problem are related. Do you have a clue how to fix this?

I fixed the problem myself. First problem was that I had to check if my view != null in the onLongPress method and check for my ListItem’s Id in the onClick method. I also fixed the problem with the changing style/colour if an item is selected. I simply forgot to call viewHolder.itemView.setActivated in my onBindViewHolder method. So thanks for the tutorial!

Hello sir, i would like to ask how to use fragments and add some data like using providers. i have my 1st app using content providers and i want to put into fragments. and it seems it needs a lot of changes to do for.

Appreciate your blog post for helping us first timers. Your search blog was helpful as well.

We’re going into production with our app Friday – potential 90,000 employees …of which I’m guessing 45% droid due to Asia/Emea but Apple is also prevelant due to corporate pushing…

Would be interested in your take on Android Stats / Future (Geographical, Age or any other indicator of the level of acceptance by a “group” – I’ve seen that iOS is still King of the World but I don’t see what age groups are into the segments) Lastly, interested in APIs – I see the future here…love Google Places/Maps apis…

I personally don’t think, iOS is king of the world. Though, granted for the enterprise context: Many execs tend to have iDevices and thus iOS often gets more attention by them. Don’t know if I’m in the position to judge about the future of mobile operating systems. But it could very well be a post on it’s own 🙂

Thank you for your example.
Running the app, only 1 item showed at a time in android 23. I didn’t understand that at first.
Checking the cardview dimensions I saw:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android&quot;
android:id="@+id/container_list_item"
android:layout_width="match_parent"
android:layout_height="match_parent"
Is 200dp not a bit high?
Changing it to the following line looked a lot better.
android:layout_height="wrap_content"
Cheers, J

Thanks for very good tutorial, but I have a problem.
I have refreshing method in which I swap adapter
public void refresh() {
ViewPager vp = (ViewPager) getActivity().findViewById(R.id.pager);
String path = ((MainPagerAdapter) vp.getAdapter()).getCurrentPath();
recyclerView.swapAdapter(new DirectoryRecyclerViewAdapter(createFileList(path), vp,this), true);
}

and selections no more work after refreshing. Can you help me with that?