我使用itemtouchhelper类来支持在我的recyclerview中拖放。当我拖动一个项目时,它会像预期的那样可视化地更新(交换行)。一旦我删除了该项,就会发生意外的“最后一次交换”,即在被拖动的项的原始位置的新值被插入到recyclerview的拖动位置,并且从拖动的项开始的所有项都被上移一行。这听起来很混乱,所以我有一个图表来演示这种行为。如果我将“a”从位置0拖动到位置3,recyclerview会在位置3显示“b”(现在是位置0),所有以“a”开头的项目都会向上移动。简言之,拖动操作“直观地”执行了两次。在这种情况下,从0到3,然后再从0到3。
这很奇怪,因为我记录了currentlist变量的内容,它显示了正确的顺序。一旦我删除了一个项目,我也会更新它在房间数据库中的位置。由于列表是通过livedata观察的,它将更新后的列表返回给mainactivity并调用onchanged,后者使用正确排序的列表(我也通过记录其内容进行了验证)将submitlist调用给适配器。
如果我关闭并重新打开应用程序,将显示正确排序的列表。这只是某种“视觉交换”,我不知道是什么原因造成的。任何帮助都将不胜感激!
编辑:如果我在这个奇怪的交换发生后调用notifydatasetchanged(),列表会执行一些不寻常的动画,但是排序正确(所以我的逻辑是正确的)。但是我使用listadapter作为我的recycleradapter和diffutil来更新我的列表。notifydatasetchanged效率低下,并且破坏了使用diffutil的整个目的。
主活动.java
private void setListObserver() {
viewModel.getAllItems().observe(this, new Observer<List<ListItem>>() {
@Override
// I have verified newList has the correct order through log statements
public void onChanged(List<ListItem> newList) {
adapterMain.submitList(newList);
}
});
}
...
// This method is called when item starts dragging
public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
...
if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
currentList = new ArrayList<>(adapterMain.getCurrentList()); // get current list from adapter
}
...
}
// This method is called when item is dropped
public void clearView(@NonNull RecyclerView recyclerView,
@NonNull RecyclerView.ViewHolder viewHolder) {
...
// I have verified that all code in this method is returning correct values through log statements.
// If I restart the app, everything is in the correct order
// this is position of the where the item was dragged to, gets its value from the onMoved method.
// it's the last "toPos" value in onMoved() after the item is dropped
int position = toPosition;
// Skip this code if item was deleted (indicated by -1). Otherwise, update the moved item
if(position != -1) {
ListItem movedItem = currentList.get(position);
// If dragged to the beginning of the list, subtract 1 from the previously lowest
// positionInList value (the item below it) and assign it the moved item. This will ensure
// that it now has the lowest positionInList value and will be ordered first.
if(position == 0) {
itemAfterPos = currentList.get(position + 1).getPositionInList();
movedItemNewPos = itemAfterPos - 1;
// If dragged to the end of list, add 1 to the positionInList value of the previously
// largest value and assign to the moved item so it will be ordered last.
} else if (position == (currentList.size() - 1)) {
itemBeforePos = currentList.get(position - 1).getPositionInList();
movedItemNewPos = itemBeforePos + 1;
// If dragged somewhere in the middle of list, get the positionInList variable value of
// the items before and after it. They are used to compute the moved item's new
// positionInList value.
} else {
itemBeforePos = currentList.get(position - 1).getPositionInList();
itemAfterPos = currentList.get(position + 1).getPositionInList();
// Calculates the moved item's positionInList variable to be half way between the
// item above it and item below it
movedItemNewPos = itemBeforePos + ((itemAfterPos - itemBeforePos) / 2.0);
}
updateItemPosInDb(movedItem, movedItemNewPos);
}
private void updateItemPosInDb(ListItem movedItem, double movedItemNewPos) {
movedItem.setPositionInList(movedItemNewPos);
viewModel.update(movedItem); // this updates the database which triggers the onChanged method
}
public void onMoved(@NonNull RecyclerView recyclerView,
@NonNull RecyclerView.ViewHolder source, int fromPos,
@NonNull RecyclerView.ViewHolder target, int toPos, int x, int y) {
Collections.swap(currentList, toPos, fromPos);
toPosition = toPos; // used in clearView()
adapterMain.notifyItemMoved(fromPos, toPos); // Not sure if this method is somehow causing the issue
}
}).attachToRecyclerView(recyclerMain);
暂无答案!
目前还没有任何答案,快来回答吧!