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

如何借助LiveData高效更新Android RecyclerView?解决增删改刷新痛点

解决MutableLiveData<List
>的高效UI刷新问题

你遇到的确实是MutableLiveData结合集合使用时的典型痛点——默认情况下,LiveData只会在集合的引用发生变化时(也就是调用setValue/postValue传入全新集合对象)才通知观察者,而集合内部的增删改操作不会触发通知。直接全量刷新RecyclerView确实效率很低,尤其是当列表数据量大的时候,下面给你分场景讲高效的实现方案:

一、先优化RecyclerView的刷新逻辑:用ListAdapter代替普通Adapter

首先最基础的优化是把你的ArticleRecyclerViewAdapter换成ListAdapter,它内置了DiffUtil,可以自动对比新旧列表的差异,只刷新真正变化的item,哪怕你传入整个集合,也不会全量刷新。

示例代码:

public class ArticleRecyclerViewAdapter extends ListAdapter<Article, ArticleViewHolder> {

    // 实现DiffUtil.ItemCallback,用来判断两个item是否是同一个,以及内容是否变化
    private static final DiffUtil.ItemCallback<Article> DIFF_CALLBACK = new DiffUtil.ItemCallback<Article>() {
        @Override
        public boolean areItemsTheSame(@NonNull Article oldItem, @NonNull Article newItem) {
            // 假设Article有唯一id,用id判断是否是同一个对象
            return oldItem.getId() == newItem.getId();
        }

        @Override
        public boolean areContentsTheSame(@NonNull Article oldItem, @NonNull Article newItem) {
            // 对比内容是否一致,比如标题、内容等
            return oldItem.getTitle().equals(newItem.getTitle())
                    && oldItem.getContent().equals(newItem.getContent());
        }
    };

    public ArticleRecyclerViewAdapter() {
        super(DIFF_CALLBACK);
    }

    @NonNull
    @Override
    public ArticleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item_article, parent, false);
        return new ArticleViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ArticleViewHolder holder, int position) {
        Article article = getItem(position);
        holder.titleTextView.setText(article.getTitle());
        holder.contentTextView.setText(article.getContent());
    }

    // ViewHolder类
    public static class ArticleViewHolder extends RecyclerView.ViewHolder {
        TextView titleTextView;
        TextView contentTextView;

        public ArticleViewHolder(@NonNull View itemView) {
            super(itemView);
            titleTextView = itemView.findViewById(R.id.tv_title);
            contentTextView = itemView.findViewById(R.id.tv_content);
        }
    }
}

之后更新数据时,只需要调用submitList方法,不需要自己维护集合:

// 在Fragment的观察者回调中
viewModel.getArticles().observe(getViewLifecycleOwner(), articles -> {
    adapter.submitList(articles);
});

这样即使你调用mArticles.setValue(articles)传入整个集合,ListAdapter也只会刷新变化的项,效率大幅提升。

二、新增/删除Article:高效更新集合并通知LiveData

方案1:基于现有集合创建新集合(推荐配合ListAdapter)

不需要直接修改原集合,而是创建一个新的集合副本,修改后再传给LiveData,这样既触发LiveData的通知,又能让ListAdapter高效计算差异:

public class ArticleViewModel extends ViewModel {
    private final MutableLiveData<List<Article>> mArticles = new MutableLiveData<>();

    // 初始化时给一个空集合
    public ArticleViewModel() {
        mArticles.setValue(new ArrayList<>());
    }

    public void addArticle(Article newArticle) {
        List<Article> currentList = new ArrayList<>(mArticles.getValue());
        currentList.add(newArticle);
        mArticles.setValue(currentList);
    }

    public void deleteArticle(int index) {
        List<Article> currentList = new ArrayList<>(mArticles.getValue());
        if (index >= 0 && index < currentList.size()) {
            currentList.remove(index);
            mArticles.setValue(currentList);
        }
    }

    public MutableLiveData<List<Article>> getArticles() {
        return mArticles;
    }
}

这种方式逻辑简单,配合ListAdapter的DiffUtil,新增/删除只会刷新对应的item,不会全量刷新。

方案2:使用Observable集合(自定义LiveData监听集合变化)

如果你不想每次都创建新集合,可以用ObservableArrayList(AndroidX中的类),然后自定义一个LiveData来监听集合的变化,当集合内部增删元素时自动通知观察者:

public class ArticleListLiveData extends LiveData<List<Article>> {
    private final ObservableArrayList<Article> mObservableList = new ObservableArrayList<>();

    private final ObservableList.OnListChangedCallback<ObservableArrayList<Article>> mCallback =
            new ObservableList.OnListChangedCallback<ObservableArrayList<Article>>() {
                @Override
                public void onChanged(ObservableArrayList<Article> sender) {
                    setValue(sender);
                }

                @Override
                public void onItemRangeChanged(ObservableArrayList<Article> sender, int positionStart, int itemCount) {
                    onChanged(sender);
                }

                @Override
                public void onItemRangeInserted(ObservableArrayList<Article> sender, int positionStart, int itemCount) {
                    onChanged(sender);
                }

                @Override
                public void onItemRangeRemoved(ObservableArrayList<Article> sender, int positionStart, int itemCount) {
                    onChanged(sender);
                }

                @Override
                public void onItemRangeMoved(ObservableArrayList<Article> sender, int fromPosition, int toPosition, int itemCount) {
                    onChanged(sender);
                }
            };

    @Override
    protected void onActive() {
        super.onActive();
        mObservableList.addOnListChangedCallback(mCallback);
    }

    @Override
    protected void onInactive() {
        super.onInactive();
        mObservableList.removeOnListChangedCallback(mCallback);
    }

    public void addArticle(Article article) {
        mObservableList.add(article);
    }

    public void deleteArticle(int index) {
        if (index >= 0 && index < mObservableList.size()) {
            mObservableList.remove(index);
        }
    }

    public ObservableArrayList<Article> getList() {
        return mObservableList;
    }
}

然后在ViewModel中使用这个自定义LiveData:

public class ArticleViewModel extends ViewModel {
    private final ArticleListLiveData mArticles = new ArticleListLiveData();

    public ArticleListLiveData getArticles() {
        return mArticles;
    }

    public void addArticle(Article newArticle) {
        mArticles.addArticle(newArticle);
    }

    public void deleteArticle(int index) {
        mArticles.deleteArticle(index);
    }
}

这种方式不需要每次创建新集合,集合内部变化时会自动通知LiveData,同样配合ListAdapter可以高效刷新UI。

三、修改Article的标题/内容:让数据本身可观察

当你需要修改Article的属性时,有两种高效的方式:

方案1:让Article的属性用ObservableField

把Article的标题、内容换成ObservableField,这样属性变化时可以直接通知UI更新,不需要修改整个集合:

public class Article {
    private final int id;
    public final ObservableField<String> title = new ObservableField<>();
    public final ObservableField<String> content = new ObservableField<>();

    public Article(int id, String title, String content) {
        this.id = id;
        this.title.set(title);
        this.content.set(content);
    }

    public int getId() {
        return id;
    }
}

然后在ViewHolder中监听属性变化:

@Override
public void onBindViewHolder(@NonNull ArticleViewHolder holder, int position) {
    Article article = getItem(position);
    // 监听标题变化
    article.title.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
        @Override
        public void onPropertyChanged(Observable sender, int propertyId) {
            holder.titleTextView.setText(article.title.get());
        }
    });
    // 监听内容变化
    article.content.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
        @Override
        public void onPropertyChanged(Observable sender, int propertyId) {
            holder.contentTextView.setText(article.content.get());
        }
    });
    // 初始化显示
    holder.titleTextView.setText(article.title.get());
    holder.contentTextView.setText(article.content.get());
}

之后修改Article的标题时,直接设置article.title.set("新标题"),UI会自动更新,不需要通知LiveData或者Adapter。

方案2:修改Article后更新LiveData(配合ListAdapter)

如果不想用ObservableField,也可以修改Article的属性后,创建一个新的集合副本传给LiveData,ListAdapter会通过DiffUtil检测到内容变化,只刷新对应的item:

public void updateArticleTitle(int index, String newTitle) {
    List<Article> currentList = new ArrayList<>(mArticles.getValue());
    if (index >= 0 && index < currentList.size()) {
        Article article = currentList.get(index);
        article.setTitle(newTitle);
        mArticles.setValue(currentList);
    }
}

因为ListAdapter的areContentsTheSame会对比新旧Article的内容,所以只会刷新这个修改了的item,不会全量刷新。

总结

最推荐的组合是:ListAdapter + 创建新集合副本更新LiveData,这种方式逻辑简单,而且能保证高效的UI刷新。如果需要更细粒度的属性变化通知,可以让Article的属性使用ObservableField,这样不需要依赖LiveData的通知就能更新UI。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:57:44