java - RecyclerView 项目选择抛出错误

标签 java android android-recyclerview

我尝试在 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();
                }
            };
        }

堆栈跟踪 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 ,接受的答案建议传递自定义 ItemKeyProvider 而不是 StableIdKeyProvider。因此,这样做时我遇到了这个错误。

堆栈跟踪 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();
        }
    }

P.S:wordAdapter.setHasStableIds(true) 在将适配器设置为 RecyclerView

之前完成

最佳答案

在你的堆栈跟踪中:

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)} 

在上面的错误中,它表示对于列表中的位置 1 和 2,您使用相同的 ID,但它必须是唯一的。为了与选择跟踪器一起使用,请确保您有唯一的 ID。 通知列表您有稳定的 ID

setHasStableIds(true)

在 RecyclerView.Adapter 中,您需要确保每个适配器都使用唯一的

public abstract class WordAdapter extends RecyclerView.Adapter {
  private List<Item> itemsList = new ArrayList<>();
  //other override methods

  @Override
    public long getItemId(int position) {
        return position; // here each value must be unique either position or data unique id
    }
}

关于java - RecyclerView 项目选择抛出错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56180020/

相关文章:

java - 从文本文件中读取数据并将其保存到二维数组中

android - 在离线模式下使用 Gradle 在 Redhat 中构建 Android APK

android - 在 Phonegap 的 inappbrowser 中禁用缩放按钮

android - Recycler View (水平)有两个项目占父宽度的 50%

android - 无法将 recyclerview 添加到 fragment

java - 如何使用 Perl 将输入管道输入到 Java 应用程序?

java - 如何使用 Spring ClassPathResource : with classpath: or classpath*: and leading/or not?

由分隔符分隔的十进制范围的 Java 正则表达式

android - IOError : [Errno 2] No such file or directory: u'/. ......./RetroApp-debug.apk'

android - RecyclerView inside CoordinatorLayout,AppBarLayout 滚动问题