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