1. 程式人生 > >RecyclerView新增和刪除操作notifyDataSetChanged依舊會導致item混亂的解決辦法

RecyclerView新增和刪除操作notifyDataSetChanged依舊會導致item混亂的解決辦法

記錄一個自己犯的蠢問題

@Override
    public void onBindViewHolder(final ViewHolder holder, int position) {
        final int pos = position;
 
        if(!holder.add.hasOnClickListeners()){
            holder.add.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    infoList.add(pos,new TeacherChangeGradeInfo());
                    Log.e("add POS:",pos+",size:"+infoList.size());
                    notifyItemInserted(pos);//通知演示插入動畫
                    notifyItemRangeChanged(pos,infoList.size()-pos);//通知資料與介面重新繫結
                }
            });

            holder.delete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    infoList.remove(pos);
                    Log.e("delete POS:",pos+",size:"+infoList.size());
                    notifyDataSetChanged();
//                    notifyItemRemoved(pos);//通知演示插入動畫
//                    notifyItemRangeChanged(0,infoList.size());//通知資料與介面重新繫結
                }
            });
            
        }
    }

我要做到的是點選item上的新增和刪除按鈕能夠正確新增和刪除item項,但在實際中item位置混亂,經常越界報錯

無論是使用

notifyItemInserted(pos);//通知演示插入動畫
notifyItemRangeChanged(pos,infoList.size()-pos);//通知資料與介面重新繫結
還是
notifyDataSetChanged();

都是一樣的效果,幾番查詢似乎找到了解決方案,onBindViewHolder方法的position不是實時更新的,遂改為

final int pos = holder.getLayoutPosition();

懷著期待再次除錯,又崩了,並且問題還是一樣。

在stackoverflow上都沒有找到方案,萬念俱灰。

根據“大多數人在網上找不到解決方案的問題只有兩種,一種是閉源的,一種是弱智的”法則,我終於找到了真相

final int pos = holder.getLayoutPosition();

pos是在onClick方法外呼叫的,也就是說對於同一ViewHolder的pos值在建立後其實一直沒有變……

最後解決方案,在onClick方法內呼叫此方法

public void onClick(View view) {
                    final int pos = holder.getLayoutPosition();
                    infoList.add(pos,new TeacherChangeGradeInfo());
                    Log.e("add POS:",pos+",size:"+infoList.size());
                    notifyDataSetChanged();
//                    notifyItemInserted(pos);//通知演示插入動畫
//                    notifyItemRangeChanged(pos,infoList.size()-pos);//通知資料與介面重新繫結
                }

就解決了問題。

另外,使用notifyDataSetChanged和使用notifyItemInserted/notifyItemRemoved+notifyItemRangeChanged都可以,但是後者有動畫,並且重新整理的內容比較少,故推薦。