Preparation:
RecyclerView
with RecyclerView.Adapter
binded to SQLite Cursor
(via ContentProvider
&& Loader). RecyclerView
and RecyclerView.Adapter
linked with SelectionTracker
as design suggests.
SelectionTracker
builded with StableIdKeyProvider
.
On first step - delete an item:
RecyclerViews
's an item with a long press (cheers to SelectionTracker
's SelectionObserver
), draw Action Bar Context Menu, fire
the delete action, do the SQL deletion task.restartLoader
call.onLoadFinished
fired, new Cursor
obtained, onRecyclerView.Adapter
method notifyDataSetChanged
called.RecyclerView.Adapter
redraw RecyclerView
content, and all is looks
good.On second step - do the selection of some other item. Crash:
java.lang.IllegalArgumentException
at androidx.core.util.Preconditions.checkArgument(Preconditions.java:38)
at androidx.recyclerview.selection.DefaultSelectionTracker.anchorRange(DefaultSelectionTracker.java:269)
at androidx.recyclerview.selection.MotionInputHandler.selectItem(MotionInputHandler.java:60)
at androidx.recyclerview.selection.TouchInputHandler.onLongPress(TouchInputHandler.java:132)
at androidx.recyclerview.selection.GestureRouter.onLongPress(GestureRouter.java:96)
at android.view.GestureDetector.dispatchLongPress(GestureDetector.java:779)
at android.view.GestureDetector.access$200(GestureDetector.java:40)
at android.view.GestureDetector$GestureHandler.handleMessage(GestureDetector.java:293)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6669)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
What I see on first step while deletion item in progress.
While StableIdKeyProvider
do internal job with onDetached
ViewHolder
item, it don't see previously assigned ViewHolder
's position within an Adapter:
void onDetached(@NonNull View view) {
RecyclerView.ViewHolder holder = mRecyclerView.findContainingViewHolder(view);
int position = holder.getAdapterPosition();
long id = holder.getItemId();
if (position != RecyclerView.NO_POSITION && id != RecyclerView.NO_ID) {
int position
here is RecyclerView.NO_POSITION
Thats why the RecyclerView crashes after - StableIdKeyProvider
's cache contains old snapshot of ID's without deletion affected.
The question is - WHY? and HOW to renew the cache of StableIdKeyProvider
?
Another note:
While I read the RecyclerView
code, I see this comment:
* Note that if you've called {@link RecyclerView.Adapter#notifyDataSetChanged()}, until the * next layout pass, the return value of this method will be {#NO_POSITION}.
I am not understood what exactly mean this words. Perhaps I faced with described situation - notifyDataSetChanged
called in not appropriate time? Or I need to call it twice?
PS. Sorry for about literary description, there is a lot of complexity code
I got it resolved by keeping the initialization and setting selectiontracker to the adapter at the very end.
capturedThumbnailListAdapter = new CapturedThumbnailListAdapter(this);
capturedThumbnailListAdapter.setCapturedThumbnailList(capturedThumbnailList);
viewBinding.capturedImagesRv.setLayoutManager(new LinearLayoutManager(this,
LinearLayoutManager.HORIZONTAL, true));
viewBinding.capturedImagesRv.setAdapter(capturedThumbnailListAdapter);
SelectionTracker<Long> tracker = new SelectionTracker.Builder<Long>("thumb_selection",
viewBinding.capturedImagesRv, new StableIdKeyProvider(viewBinding.capturedImagesRv),
new CapturedThumbnailListAdapter.ItemLookUp(viewBinding.capturedImagesRv),
StorageStrategy.createLongStorage())
.withSelectionPredicate(SelectionPredicates.createSelectAnything())
.build();
capturedThumbnailListAdapter.setSelectionTracker(tracker);
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With