You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android:如何复制ListAdapter列表实现列表项移动并更新UI?

关于ListAdapter实现列表项移动的问题

我该如何复制现有ListAdapter的列表,以便用于移动列表项,然后通过对比新的复制列表与原列表来更新UI?

或许Android开发者在设计用于RecyclerView的ListAdapter源码时,只考虑了CRUD操作。若是如此,他们忽略了过滤、排序和移动列表项等其他重要的RecyclerView操作。这些操作仅会改变排序顺序(排序和移动项)或从原列表中移除部分项(过滤),但这难道需要自定义Adapter吗?此外,对于大型RecyclerView列表,需要将列表复制到内存中让ListAdapter“识别”新列表,这似乎违背了ListAdapter在后台线程提升效率的初衷。

我原本认为后台线程更新对稳定性和UI效率很有价值,因此将现有项目转为使用ListAdapter。我的CRUD操作运行正常,但现在面临的难题是如何实现过滤、排序和移动列表项这些功能。

我尝试移动RecyclerView中的列表项,但拖拽功能无法正常工作。以下是我至今尝试过的不同组合方法。同时,我查阅了所有关于ListAdapter的问题……但遗憾的是我完全不懂Kotlin,所以寻求Java解决方案。我遗漏了什么?


MainActivity方案#1

ItemTouchHelper.SimpleCallback itemTouchHelperCallback1 = new ItemTouchHelper.SimpleCallback(
   (ItemTouchHelper.UP | ItemTouchHelper.DOWN),0) {

    int dragFrom = -1;
    int dragTo = -1;    

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {

        int fromPos = viewHolder.getBindingAdapterPosition();
        int toPos = target.getBindingAdapterPosition();

        if (dragFrom == -1) {
            dragFrom = fromPos;
        }
        dragTo = toPos;

        cardsAdapter.moveItem(fromPos, toPos);                        
        return true;
    }  
};        
new ItemTouchHelper(itemTouchHelperCallback1).attachToRecyclerView(recyclerView); 

MainActivity方案#2(onMove()方法)

List newList = adapter.getCurrentList();
Quickcard quickcardItem = newList.get(fromPos);
newList.remove(fromPos);
newList.add(toPos, quickcardItem);
cardsAdapter.moveItem(fromPos, toPos);
cardsAdapter.notifyItemMoved(fromPos, toPos);
cardsAdapter.submitList(newList);
return true;

ListAdapter方案#1

public class CardsAdapter extends ListAdapter<Quickcard, CardsAdapter.ItemHolder> {

    private final LayoutInflater layoutInflater;

    protected CardsAdapter(@NonNull LayoutInflater layoutInflater, DiffUtil.ItemCallback<Quickcard> diffCallback) {
        super(diffCallback);
        this.layoutInflater = layoutInflater;
    }

    ... // ViewHolder代码 
     
    public void moveItem(int fromOldPos, int toNewPos) {

        // 复制ListAdapter的现有列表
        ArrayList<Quickcard> currList = new ArrayList<>(getCurrentList()); 
    
        if (fromOldPos == toNewPos) {
            return;
        }
        Collections.swap(currList, toNewPos, fromOldPos);
        notifyItemMoved(fromOldPos, toNewPos);
        submitList(currList);
    }     
}

ListAdapter方案#2(moveItem()方法)

List<Quickcard> currList = getCurrentList();
List<Quickcard> copiedList = new ArrayList<>(currList);

if (fromOldPos == toNewPos) {
    return;
}
if (fromOldPos < toNewPos) { // 项在列表中向下移动
    for (int i = fromOldPos; i < toNewPos; i++) {
    Collections.swap(copiedList, i,i + 1);
    }
} else { // 项在列表中向上移动
    for (int i = fromOldPos; i > toNewPos; i--) {
        Collections.swap(copiedList, i,i - 1);
    }
}
notifyItemMoved(fromOldPos, toNewPos);
submitList(copiedList);

ListAdapter方案#3(moveItem()方法)

// 为Model添加复制构造函数后,我还尝试了此方法
// (参考StackOverflow #48575477中@Matt的回答)

List<CustomObject> copyList = new ArrayList<>();
for(CustomObject obj : parentList) {
    copyList.add(new CustomObject(obj));
}

ViewModel方案

// mTodos是ViewModel中的MutableLiveData<List>
List<Todo> todos = mTodos.getValue();
ArrayList<Todo> clonedTodos = new ArrayList<Todo>(todos.size());
    for(int i = 0; i < todos.size(); i++){
        clonedTodos.add(new Todo(todos.get(i)));
    }        
    mTodos.postValue(clonedTodos);

内容的提问来源于stack exchange,提问作者AJW

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 11:57:04