Renew StableIdKeyProvider cache and RecyclerView/SelectionTracker crash on new selection after item removed

I am ended up to play with StableIdKeyProvider and switch to plain my own implementation of ItemKeyProvider:

new ItemKeyProvider<Long>(ItemKeyProvider.SCOPE_MAPPED) {
                    @Override
                    public Long getKey(int position) {
                        return adapter.getItemId(position);
                    }

                    @Override
                    public int getPosition(@NonNull Long key) {
                        RecyclerView.ViewHolder viewHolder = recyclerList.findViewHolderForItemId(key);
                        return viewHolder == null ? RecyclerView.NO_POSITION : viewHolder.getLayoutPosition();
                    }
                }

Crash is gone, RecyclerView's navigation/selection/modification looks OK. What about StableIdKeyProvider ?.. Hmm, may be it is not designed to work with mutable content of RecyclerView.


My problem was solved by setting setHasStableIds(true) in Recycle view adapter and overriding getItemId, It seems that Tracker require both setHasStableIds(true) and overrindinggetItemId in adapter I got this error after setting stable Ids true without overriding getItemId

 init {
    setHasStableIds(true)
}
override fun getItemId(position: Int) = position.toLong()
override fun getItemViewType(position: Int) = position

I encountered the same issue with the StableIdKeyProvider. Writing a custom implementation of ItemKeyProvider seems to do the trick. Here's a basic Kotlin implementation you can use when building a selection tracker for a RecyclerView:

class RecyclerViewIdKeyProvider(private val recyclerView: RecyclerView)
    : ItemKeyProvider<Long>(ItemKeyProvider.SCOPE_MAPPED) {

    override fun getKey(position: Int): Long? {
        return recyclerView.adapter?.getItemId(position)
                ?: throw IllegalStateException("RecyclerView adapter is not set!")
    }

    override fun getPosition(key: Long): Int {
        val viewHolder = recyclerView.findViewHolderForItemId(key)
        return viewHolder?.layoutPosition ?: RecyclerView.NO_POSITION
    }
}