这是大概十多天前遇到的问题,只是一直懒得记录下来,现在补上。
是这样的,我需要实现一个列表并且要支持上下拖动,代码的实现跟网上大部分的实现类似,代码如下:
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
@Override
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
// 支持上下拖动
int dragFlags = ItemTouchHelper.DOWN | ItemTouchHelper.UP;
// swipeFlags为0,即不支持滑动
int swipeFlags = 0;
return makeMovementFlags(dragFlags,swipeFlags);
}
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int originalPosition = viewHolder.getAdapterPosition();
int targetPosition = target.getAdapterPosition();
/***********************代码段一****************************/
mAdapter.notifyItemMoved(originalPosition,targetPosition);
Collections.swap(mList,originalPosition,targetPosition);
/***********************代码段一 END********************/
return true;
}
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
});
itemTouchHelper.attachToRecyclerView(recyclerView);
上面的代码,在我看来是没有任何问题的,直到在一次偶然的机会中,我发现mList里的数据的顺序和显示的数据的顺序不一致!我第一反应是这怎么可能? 只有在初始化和onMove里才会操作到mList,也没有涉及到子线程。既然出现了问题,那就要找原因。debug了十多次,无法复现,只能利用Logger,在代码段一的前后和在onSelectedChange里打印相关数据,在一顿操作后,复现了,显示的数据和最后打印出来的mList的数据的顺序不一致。然后就是从那一大串的log里找出原因了,终于在log中一处发现originalPosition和targetPosition的差值的绝对值不是1,是2,这就是数据不一致的原因。现有一个初始数据如下:
position | 显示的数据 | mList的数据 |
---|---|---|
0 | A | A |
1 | B | B |
2 | C | C |
现假设originPosition为0,targetPosition为2。在mAdapter执行notifyItemMoved和对mList进行swap操作后,如下:
position | 显示的数据 | mList的数据 |
---|---|---|
0 | B | C |
1 | C | B |
2 | A | A |
很明显,数据的顺序不一致。在后来的测试中发现,对item进行快速上下拖动时就会出现originalPosition与targetPosiion的差值的绝对值不为1的情况。
解决方案也非常简单, 将Collections.swap(mList,originalPosition,targetPosition);替换为以下代码即可:
String str = mList.remove(originalPosition);
mList.add(targetPosition,str);