RecyclerView ItemTouchHelper getAdapterPosition() 在快速滑动时返回错误值

Posted

技术标签:

【中文标题】RecyclerView ItemTouchHelper getAdapterPosition() 在快速滑动时返回错误值【英文标题】:RecyclerView ItemTouchHelper getAdapterPosition() returns wrong value on fast swipe 【发布时间】:2018-01-10 22:35:40 【问题描述】:

我对 RecyclerView + 滑动删除 + 撤消在快餐栏的帮助下遇到问题。每当我尝试快速滑动 3+ 项以删除它们时,viewHolder.getAdapterPosition(); 返回一个错误的值。好像反应不那么快。

RecyclerView 列表示例:

    测试1 测试2 测试3 测试4

所以,如果我快速扫开 Test3,Test2 然后 Test1 viewHolder.getAdapterPosition(); 返回位置 2、2 和 0。 正确的返回值必须是 2、1 和 0。

对于两个项目,一切正常,返回 2,然后返回 1。

注意:最后一个位置总是在 2 秒后返回,因为snackbar 超时然后该项目被删除。一旦下一个项目被刷掉,之前显示的小吃店就会被关闭。

任何想法如何解决这个问题? 我想了好几个小时。

ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT) 
        @Override
        public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) 
            return false;
        

        @Override
        public void onSwiped(final RecyclerView.ViewHolder viewHolder, int swipeDir) 

            final int position = viewHolder.getAdapterPosition();

            FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
            rusure = Snackbar.make(fab, getResources().getString(R.string.rule_deleted), Snackbar.LENGTH_SHORT).addCallback(new Snackbar.Callback() 
                @Override
                public void onDismissed(Snackbar snackbar, int event) 

                    switch(event) 
                        case Snackbar.Callback.DISMISS_EVENT_ACTION:
                            rulesAdapter.notifyDataSetChanged();
                            break;
                        case Snackbar.Callback.DISMISS_EVENT_TIMEOUT:
                        case Snackbar.Callback.DISMISS_EVENT_CONSECUTIVE:
                        case Snackbar.Callback.DISMISS_EVENT_MANUAL:

                            Log.d("test", Integer.toString(position));
                            if(position!=-1 && position<arrayList.size())

                                // Define 'where' part of query.
                                String selection = DatabaseTablesColums.FeedEntry._ID + " LIKE ?";
                                // Specify arguments in placeholder order.
                                String[] selectionArgs = Integer.toString(arrayList.get(position).getId());
                                // Issue SQL statement.


                                arrayList.remove(position);
                                rulesAdapter.notifyItemRemoved(position);
                                rulesAdapter.notifyItemRangeChanged(position, rulesAdapter.getItemCount());


                                db.delete(DatabaseTablesColums.FeedEntry.TABLE_NAME, selection, selectionArgs);
                                // Remove item from backing list here
                            

                            break;
                    
                

                @Override
                public void onShown(Snackbar snackbar) 
                
            ).setAction(getResources().getString(R.string.undo), new View.OnClickListener() 
                @Override
                public void onClick(View v) 
                
            );
            rusure.show();


        
    );

    itemTouchHelper.attachToRecyclerView(recyclerView);

【问题讨论】:

【参考方案1】:

看起来您正在从支持数据存储中删除该项目,在您的情况下,它是 arrayList 并且仅在 SnackBar 关闭后通知适配器。

因此,如果您在第一个 Snackbar 关闭之前滑动下一项,RecyclerView 适配器不知道第一项已从适配器中删除。所以它给了你一个错误的位置。

您应该从后备数据存储 (arrayList) 中删除该项目,并在滑动项目后立即调用 notifyItemRemoved(),而不是在 Snackbar 关闭后更新。

不过,您只能在 SnackBar 关闭后更新数据库。

【讨论】:

谢谢!以及如何再次使用arrayList.remove()检索从arrayList中删除的项目? 如果您的意思是如果用户点击 SnackBar 上的 Undo 后再次想要该项目,您可以有一个主列表和一个后备列表。后备列表是用于在 RecyclerView 中显示项目的列表。滑动项目时从后备列表中删除项目。如果单击撤消,您可以从主列表中获取该项目。如果未按下撤消,则必须从主列表中删除该项目并将其更新到数据库中。 好主意,谢谢!我真的很想自己弄清楚事情,但这花了我这么多小时没有结果;) 只剩下一个问题:如何将新的数组列表加载到我的 rulesAdapter 中?那可能吗?还是我需要一个新的 RecyclerView 适配器? 我假设你是编写 rulesAdapter 类的人。如果是这样,您可以通过构造函数传递另一个列表。但是,我建议您从适配器本身内部的原始列表创建一个新的 ArrayList 用于支持列表,如下所示: List backingList = new ArrayList(oldList);

以上是关于RecyclerView ItemTouchHelper getAdapterPosition() 在快速滑动时返回错误值的主要内容,如果未能解决你的问题,请参考以下文章

RecyclerView详解

RecyclerView

RecyclerView嵌套RecyclerView问题

RecyclerView小结

RecyclerView系列:RecyclerView嵌套RecyclerView(BaseRecyclerViewAdapterHelper实现)

recyclerview怎么监听滑动事件