Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/181.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 更新StableIdKeyProvider缓存和RecyclerView/SelectionTracker在删除项目后因新选择而崩溃_Java_Android_Android Recyclerview - Fatal编程技术网

Java 更新StableIdKeyProvider缓存和RecyclerView/SelectionTracker在删除项目后因新选择而崩溃

Java 更新StableIdKeyProvider缓存和RecyclerView/SelectionTracker在删除项目后因新选择而崩溃,java,android,android-recyclerview,Java,Android,Android Recyclerview,准备: RecyclerView与RecyclerView.Adapter绑定到SQLiteCursor(通过ContentProvider和&Loader)RecyclerView和RecyclerView.Adapter链接到SelectionTrackeras。 SelectionTracker使用StableIdKeyProvider构建 在第一步中-删除项目: 长按选择RecyclerViews是一个项目(为SelectionTracker的SelectionObserver干杯),绘

准备:

RecyclerView
RecyclerView.Adapter
绑定到SQLite
Cursor
(通过
ContentProvider
和&Loader)
RecyclerView
RecyclerView.Adapter
链接到
SelectionTracker
as。
SelectionTracker
使用
StableIdKeyProvider
构建

在第一步中-删除项目:

  • 长按选择
    RecyclerViews
    是一个项目(为
    SelectionTracker
    SelectionObserver
    干杯),绘制操作栏上下文菜单,启动 在删除操作中,执行SQL删除任务
  • SQL删除结束后,使用
    更新游标加载程序
    restartLoader
    调用
  • onLoadFinished
    已激发,新的
    光标已获得,位于
    RecyclerView.Adapter
    method
    notifyDataSetChanged
    已调用
  • RecyclerView.Adapter
    redraw
    RecyclerView
    内容,所有内容都是外观 好
  • 第二步-选择其他项目。崩溃:

    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)
    
    我在删除项目时第一步看到的内容。 当
    StableIdKeyProvider
    使用
    onDetached
    ViewHolder
    项执行内部作业时,它看不到先前分配的
    ViewHolder
    在适配器中的位置:

       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
    这里是
    RecyclerView。无位置

    这就是为什么在-
    StableIdKeyProvider
    的缓存包含旧的ID快照而不影响删除后,RecyclerView崩溃的原因

    问题是——为什么?以及如何更新
    StableIdKeyProvider
    的缓存

    另一项说明: 当我阅读
    RecyclerView
    代码时,我看到以下评论:

    我不明白这句话的确切意思。也许我遇到了所描述的情况-
    notifydatasetchange
    在不合适的时间调用?或者我需要打两次电话

    附言。
    很抱歉,关于文字描述,有很多复杂的代码

    我最终使用了
    StableIdKeyProvider
    并切换到我自己的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();
                        }
                    }
    
    新建ItemKeyProvider(ItemKeyProvider.SCOPE\u映射){
    @凌驾
    公共长getKey(int位置){
    返回适配器.getItemId(位置);
    }
    @凌驾
    public int getPosition(@NonNull长键){
    RecyclerView.ViewHolder ViewHolder=recyclerList.findViewHolderForItemId(键);
    return viewHolder==null?RecyclerView.NO_位置:viewHolder.getLayoutPosition();
    }
    }
    
    崩溃消失,
    RecyclerView
    的导航/选择/修改看起来正常。
    那么,StableIdKeyProvider呢?。。嗯,可能它不是为处理
    RecyclerView
    的可变内容而设计的

    我在StableIdKeyProvider中遇到了同样的问题。编写ItemKeyProvider的自定义实现似乎可以做到这一点。以下是一个基本的Kotlin实现,您可以在为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
        }
    }
    
    类RecycleServiceWidKeyProvider(私有val RecycleView:RecycleView)
    :ItemKeyProvider(ItemKeyProvider.SCOPE\u映射){
    覆盖趣味getKey(位置:Int):长{
    返回recyclerView.adapter?.getItemId(位置)
    ?:抛出IllegalStateException(“未设置RecyclerView适配器!”)
    }
    覆盖位置(键:长):Int{
    val viewHolder=recyclerView.findViewHolderForItemId(键)
    返回viewHolder?.layoutPosition?:RecyclerView.NO\u位置
    }
    }
    
    我的问题通过在循环视图适配器中设置
    sethasstableId(true)
    并重写
    getItemId
    得到了解决,似乎跟踪器同时需要
    sethasstableId(true)
    和在适配器中重写
    getItemId
    在未重写getItemId>的情况下设置了稳定的Ids true后出现了这个错误

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

    遇到同样的问题,经过长时间的搜索,我找到了答案: 您只需要在Recycler Adapter视图中重写该方法

    override fun getItemId(position: Int): Long = position.toLong()
    

    在我的例子中,问题与
    ViewHolder
    中的
    ItemDetailsLookup.ItemDetails
    的初始化有关。事实证明,
    getAdapterPosition()
    可能在
    ViewHolder
    绑定期间返回错误的位置。解决方案是在调用
    itemtailsLookup中的
    getAdapterPosition()
    时调用
    getAdapterPosition()
    ,通过将初始化和selectiontracker设置到适配器的最末端,我解决了这个问题

        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);
    
    capturedThumbnailListAdapter=新的capturedThumbnailListAdapter(此);
    CapturedThumbNailtListAdapter.setCapturedThumbNailtList(CapturedThumbNailtList);
    viewBinding.capturedImagesRv.setLayoutManager(新的LinearLayoutManager(此,
    LinearLayoutManager.HORIZONTAL,true));
    viewBinding.capturedImagesRv.setAdapter(CapturedHumbnailListAdapter);
    SelectionTracker tracker=新建SelectionTracker.Builder(“thumb_selection”,
    viewBinding.capturedImagesRv,新的StableIdKeyProvider(viewBinding.capturedImagesRv),
    新CapturedHumbnailListAdapter.ItemLookUp(viewBinding.capturedImagesRv),
    StorageStrategy.createLongStorage())
    .withSelectionPredicate(SelectionPredicates.createSelectAnything())
    .build();
    capturedThumbnailListAdapter.setSelectionTracker(跟踪器);
    
    问题不在这里;言行一致

    /** Constructor */
    public SomeAdapter() {
        this.setHasStableIds(true);
    }
    
    适配器确实必须
    @覆盖公共长getItemId()


    这也发生在我使用SelectionTracker的RecyclerView上。此解决方案使用自定义ItemKeyProvider f替换Google的StableIdKeyProvider
    /** Constructor */
    public SomeAdapter() {
        this.setHasStableIds(true);
    }
    
    @Override
    public long getItemId(int position) {
        if(this.mItems == null) {return -1L;}
        return this.mItems.get(position).getId();
    }