java—在拖放后调用listadapter的submitlist以更新recyclerview的更有效方法

q5lcpyga  于 2021-06-30  发布在  Java
关注(0)|答案(1)|浏览(596)

我使用itemtouchhelper类来支持在我的recyclerview中拖放。我有一个实现,如预期的工作,但它似乎是非常低效的。在onmoved方法中,我获取列表的当前版本,交换拖动的项,然后用列表的新版本调用submitlist。问题是,每次发生交换时都会调用onmoved,交换在列表中拖动时会逐个执行。因此,如果位置1处的项目被拖到位置11,则每次交换时都会从(1->2)、(2->3)等处调用onmoved。这意味着我得到了列表的一个新版本,并在拖动完成时调用submitlist 10次。
我试过的:
我试着在拖动完成后用更新的列表调用submitlist,但是没有改变。在调用submitlist之前,我已经记录了适配器的getcurrentlist(),它显示了原始的未更改列表(这是预期的)。我已经记录了mainactivity的currentlist变量,它显示了更新的交换列表。我将currentlist变量传递给submitlist,然后记录适配器的getcurrentlist(),它仍然显示原始的未更改列表。我读过这篇文章,但没有一个建议的解决方案。任何帮助都将不胜感激!
编辑:我还在适配器中使用diffutil。
主活动.java

...

private void createItemTouchHelper() {
    new ItemTouchHelper(new ItemTouchHelper.SimpleCallback(
        ItemTouchHelper.UP | ItemTouchHelper.DOWN,
        ItemTouchHelper.START | ItemTouchHelper.END) {

    // To track changes when user drags
    List<ListItem> currentList;

    // This method is called when user starts dragging an item
    public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState) {
      if (actionState == ItemTouchHelper.ACTION_STATE_DRAG) {

        // get the current list from the adapter to modify
        // have to create new list because getCurrentList() returns an unmodifiable list
        currentList = new ArrayList<>(adapterMain.getCurrentList()); 
      }
    }

    // This method gets called when user releases the dragged item
    public void clearView(@NonNull RecyclerView recyclerView,
                            @NonNull RecyclerView.ViewHolder viewHolder) { 

      adapterMain.submitList(currentList); // Does not update the list in the adapter
    }

    // gets called each time a row is dragged by one position
    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); // update the local ArrayList

        // This "visually" moves the item in RecyclerView but it doesn't update the list in the adapter
        adapterMain.notifyItemMoved(fromPos, toPos); 
    }
  }).attachToRecyclerView(recyclerMain);
}

这是onmoved方法的工作版本。我不需要在onselectedchanged()或clearview()中放入任何代码就可以让它工作。似乎效率很低。。。

public void onMoved(@NonNull RecyclerView recyclerView,
                          @NonNull RecyclerView.ViewHolder source, int fromPos,
                          @NonNull RecyclerView.ViewHolder target, int toPos, int x, int y) {

        // adapterMain.getCurrentList() returns an unmodifiable list, convert to new ArrayList
        currentList = new ArrayList<>(adapterMain.getCurrentList());
        Collections.swap(currentList, toPos, fromPos);
        adapterMain.submitList(currentList); // why does submitList work here but not in the clearView method?
        // adapterMain.notifyItemMoved(fromPos, toPos); // this is not needed when I call submitList here
      }

recycleradaptermain.java文件

public class RecyclerAdapterMain extends ListAdapter<ListItem, RecyclerAdapterMain.ListItemHolder> {

  public RecyclerAdapterMain() {
    super(DIFF_CALLBACK);
  }

    private static final DiffUtil.ItemCallback<ListItem> DIFF_CALLBACK = new DiffUtil.ItemCallback<ListItem>() {
    @Override
    public boolean areItemsTheSame(@NonNull ListItem oldItem, @NonNull ListItem newItem) {
      return oldItem.getId() == newItem.getId();
    }

    @Override
    public boolean areContentsTheSame(@NonNull ListItem oldItem, @NonNull ListItem newItem) {
      return oldItem.equals(newItem);
    }
  };

...

}
cnjp1d6j

cnjp1d6j1#

diffutil将完美地处理这个问题,“diffutil是一个实用程序类,它计算两个列表之间的差异并输出一个更新的列表”。diffutil设计用于与recyclerviewer一起使用。
https://developer.android.com/reference/androidx/recyclerview/widget/diffutil
这里是diffutil代码实验室,它在kotlin,但它应该提供足够的信息让你去。https://developer.android.com/codelabs/kotlin-android-training-diffutil-databinding#0

相关问题