How to use recyclerview-selection by setting the key as a string?

Viewed 1756

Using the android library androidx.recyclerview.selection, I have tried to implement multiple selection in RecyclerView following the tutorials here and here.

But, I want my key to be a String, instead of Long, but I am facing two errors as follows:

tracker = SelectionTracker.Builder<String>(
    "selection_id",
    recyclerView,
    StableIdKeyProvider(recyclerView),    // this line shows error
    MyItemDetailsLookup(recyclerView),
    StorageStrategy.createStringStorage()    // this line shows error
    ).withSelectionPredicate(
        SelectionPredicates.createSelectAnything()
    ).build()

I want some details about how is ItemKeyProvider implemented for a String, and secondly,

StorageStrategy.createStringStorage() // this shows error
StorageStrategy.createLongStorage()   // this doesn't show error

why is that happening, when everywhere I have replaced the generic type from Long to String?

1 Answers

According to the docs, StorageStrategy is used for storing keys in saved state,

/* for    Long    keys */    StorageStrategy.createLongStorage()
/* for   String   keys */    StorageStrategy.createStringStorage()
/* for Parcelable keys */    StorageStrategy.createParcelableStorage(Class)

Also, according to the docs, StableIdKeyProvider provides for keys of type Long. That is why, your StorageStrategy is showing error because it is expecting Long keys.

To provide String keys, you have to create your own ItemKeyProvider class. For more details on ItemKeyProvider, you can refer the docs here.

This is how you can implement ItemKeyProvider class for String keys:

class MyItemKeyProvider(private val rvAdapter: MyAdapter): ItemKeyProvider<String>(SCOPE_CACHED) {
    override fun getKey(position: Int): String = rvAdapter.getItem(position).myKey
    override fun getPosition(key: String): Int = rvAdapter.getPosition(key)
}

and in MyAdapter:

class MyAdapter(private val myList: ArrayList<MyModel>): RecyclerView.Adapter<MyAdapter.MyViewHolder>() {
    // functions used in MyItemKeyProvider
    fun getItem(position: Int) = myList[position]
    fun getPosition(key: String) = myList.indexOfFirst { it.myKey == key }

    // other functions
}

where MyModel is something like this:

data class MyModel (
    val myKey: String,
    // other data
)

Now, you can simply build your SelectionTracker like this:

myTracker = SelectionTracker.Builder(
        "my_selection_id",
        recyclerView,
        MyItemKeyProvider(rvAdapter),
        MyItemDetailsLookup(recyclerView),
        StorageStrategy.createStringStorage()
    ).withSelectionPredicate(
        SelectionPredicates.createSelectAnything()
    ).build()

Note that you should not write the following code in your Adapter if you are not using StableIdKeyProvider:

init { setHasStableIds(true) }

otherwise it will show this error:

Attempt to invoke virtual method 'boolean androidx.recyclerview.widget.RecyclerView$ViewHolder.shouldIgnore()' on a null object reference

This tutorial shows how to implement recyclerview-selection with Long keys, also showing how to implement your own ItemKeyProvider class for Long keys.

To implement recyclerview-selection with Parcelable keys, I have found a sample code here.

Related