我尝试在 SelectionTracker 的帮助下在 RecyclerView 中实现项目选择功能,但是得到了 IllegalArgumentException ,并且堆栈跟踪并不直观,因为仅显示元数据。
这就是我构建跟踪器的方式
wordAdapter.tracker = new SelectionTracker.Builder<Long>(
"mySelectionId",
recyclerView,
new StableIdKeyProvider(recyclerView),
new MyDetailsLookUp(recyclerView),
StorageStrategy.createLongStorage()
).withSelectionPredicate(
SelectionPredicates.<Long>createSelectAnything()
).build();
MyDetailsLookUp 类
class MyDetailsLookUp extends ItemDetailsLookup<Long> {
RecyclerView recyclerView;
MyDetailsLookUp(RecyclerView recyclerView) {
this.recyclerView = recyclerView;
}
@Nullable
@Override
public ItemDetails<Long> getItemDetails(@NonNull MotionEvent e) {
View view = recyclerView.findChildViewUnder(e.getX(), e.getY());
if (view != null) {
// getting individual view holders
return ((WordAdapter.MyViewHolder) recyclerView.getChildViewHolder(view)).getItemDetails();
}
return null;
}
}
WordAdapter 中 ViewHolder 中的getItemDetails 方法
ItemDetailsLookup.ItemDetails<Long> getItemDetails(){
return new ItemDetailsLookup.ItemDetails<Long>(){
@Override
public int getPosition() {
return getAdapterPosition();
}
@Nullable
@Override
public Long getSelectionKey() {
return getItemId();
}
};
}
Stacktrace 1
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:778)
at android.view.GestureDetector.-wrap0(Unknown Source:0)
at android.view.GestureDetector$GestureHandler.handleMessage(GestureDetector.java:293)
at android.os.Handler.dispatchMessage(Handler.java:105)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
令人惊讶的是,我已经在Kotlin中实现了相同的代码,并且在那儿运行良好。我发现有类似问题this的SO帖子,该接受的答案建议传递自定义 ItemKeyProvider 而不是 StableIdKeyProvider 。因此,这样做会打我这个错误。
Stacktrace 2
java.lang.IllegalStateException: Two different ViewHolders have the same stable ID. Stable IDs in your adapter MUST BE unique and SHOULD NOT change.
ViewHolder 1:ViewHolder{987472c position=1 id=-1, oldPos=-1, pLpos:-1}
View Holder 2:ViewHolder{e50e5f5 position=2 id=-1, oldPos=-1, pLpos:-1 not recyclable(1)} androidx.recyclerview.widget.RecyclerView{617d73 VFED..... .F....ID 42,42-1038,1542 #7f08007b app:id/recyclerview}, adapter:com.example.roomwordssample.WordAdapter@7ada430, layout:androidx.recyclerview.widget.GridLayoutManager@a15b8a9, context:com.example.roomwordssample.Main2Activity@ca1d275
at androidx.recyclerview.widget.RecyclerView.handleMissingPreInfoForChangeError(RecyclerView.java:4058)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep3(RecyclerView.java:3982)
at androidx.recyclerview.widget.RecyclerView.dispatchLayout(RecyclerView.java:3652)
at androidx.recyclerview.widget.RecyclerView.consumePendingUpdateOperations(RecyclerView.java:1877)
at androidx.recyclerview.widget.RecyclerView$1.run(RecyclerView.java:407)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:911)
at android.view.Choreographer.doCallbacks(Choreographer.java:723)
at android.view.Choreographer.doFrame(Choreographer.java:655)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:897)
at android.os.Handler.handleCallback(Handler.java:789)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:164)
at android.app.ActivityThread.main(ActivityThread.java:6541)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
更新的跟踪器
wordAdapter.tracker = new SelectionTracker.Builder<Long>(
"mySelectionId",
recyclerView,
new GetItemDetails(recyclerView, ItemKeyProvider.SCOPE_MAPPED),
new MyDetailsLookUp(recyclerView),
StorageStrategy.createLongStorage()
).withSelectionPredicate(
SelectionPredicates.<Long>createSelectAnything()
).build();
CustomItemKeyProvider
class CustomItemKeyProvider extends ItemKeyProvider<Long> {
RecyclerView recyclerView;
CustomItemKeyProvider(RecyclerView recyclerView, int scope) {
super(scope);
this.recyclerView = recyclerView;
}
@Nullable
@Override
public Long getKey(int position) {
return wordAdapter.getItemId(position);
}
@Override
public int getPosition(@NonNull Long key) {
RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForItemId(key);
return viewHolder == null ? RecyclerView.NO_POSITION : viewHolder.getLayoutPosition();
}
}
PS :在将适配器设置为wordAdapter.setHasStableIds(true)
RecyclerView
答案 0 :(得分:0)
在您的堆栈跟踪中:
2019-05-17 00:00:00.000
在上面的错误中,它表示列表中的位置1和2,您使用的是相同的ID,但必须唯一。为了与选择跟踪器一起使用,请确保您具有唯一的ID。 通知列表您具有稳定的ID
java.lang.IllegalStateException: Two different ViewHolders have the same stable ID. Stable IDs in your adapter MUST BE unique and SHOULD NOT change.
ViewHolder 1:ViewHolder{987472c **position=1 id=-1**, oldPos=-1, pLpos:-1}
View Holder 2:ViewHolder{e50e5f5 **position=2 id=-1**, oldPos=-1, pLpos:-1 not recyclable(1)}
在RecyclerView.Adapter中,您需要确保每个变量都使用唯一
setHasStableIds(true)