You need to enable JavaScript to run this app. DiffUtil 未调用 onBindView 或不刷新可见 ViewHolder 怎么办
优惠活动
大模型
产品
解决方案
定价
更多

DiffUtil 未调用 onBindView 或不刷新可见 ViewHolder 怎么办

DiffUtil更新后需滚动才显示新值的问题排查

当前实现场景

要做固定30条目的列表,每分钟刷新数据,为了避免滥用notifyDataSetChanged引入DiffUtil差量更新机制,目前实现如下:

自定义DiffUtil.Callback

public class DifUtil extends DiffUtil.Callback {
    private final List<Asset> oldList, newList;

    public DifUtil(List<Asset> newList, List<Asset> oldList) {
        this.oldList = oldList;
        this.newList = newList;
    }

    @Override
    public int getOldListSize() {
        return oldList.size();
    }

    @Override
    public int getNewListSize() {
        return newList.size();
    }

    @Override
    public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
        return oldList.get(oldItemPosition).getId().equals(newList.get(newItemPosition).getId());
    }

    @Override
    public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
        return oldList.get(oldItemPosition).equals(newList.get(newItemPosition));
    }

    @Nullable
    @Override
    public Object getChangePayload(int oldItemPosition, int newItemPosition) {
        return super.getChangePayload(oldItemPosition, newItemPosition);
    }
}

Adapter内的更新方法

public void updateList(List<Asset> newList) {
    DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DifUtil(newList, this.assetList));
    this.assetList.clear();
    this.assetList.addAll(newList);
    diffResult.dispatchUpdatesTo(this);
}

其他已实现逻辑

  • 重写了带payload参数的onBindViewHolder,方法签名为:
onBindViewHolder(@NonNull AssetsAdapter.ViewHolder holder, int position, @NonNull List<Object> payloads)
  • 调用更新方法仅需传入最新的列表:adapter.updateList(newAssetList);

异常表现

Adapter持有的列表数据已经完成更新,但只有滚动列表触发视图回收时,界面上才能看到最新值,达不到和notifyItemChanged()一致的即时刷新效果。


核心排查点与修复方案

按照以下顺序排查,即可解决即时刷新的问题:

  • 优先检查Asset类的equals方法实现
    你在areContentsTheSame中直接通过两个Asset对象的equals方法判断内容是否一致。如果没有手动重写Asset的equals方法,默认会比较对象的内存地址,永远不会判断内容相等;如果重写了但遗漏了需要实时更新的业务字段(比如每分钟变动的数值类字段),DiffUtil会误判条目内容无变化,不触发对应位置的notifyItemChanged通知。
    这种场景下,你虽然已经把新数据更新到了Adapter的列表中,但ViewHolder因为没有收到更新通知,仍绑定着旧数据。只有滚动时ViewHolder被回收重新执行绑定逻辑,才会读取到新列表的数据,和你遇到的现象完全匹配。
  • 确认差量计算的执行顺序
    你目前的调用顺序(先对比新旧列表计算差量→再替换Adapter持有的列表数据→最后分发更新通知)是正确的。千万不要调换为“先清空Adapter旧列表、添加新数据,再计算Diff差量”,这种顺序会导致DiffUtil拿内容完全一致的两个列表做对比,计算结果为空,不会触发任何界面更新通知。
  • 检查三参数onBindViewHolder的绑定逻辑
    如果你重写了带payload参数的onBindViewHolder,必须保证当payloads为空时,执行和两参数onBindViewHolder完全一致的绑定逻辑,将item数据正确设置到ViewHolder的控件上。不要把全量绑定逻辑只写在payload非空的分支里,否则DiffUtil分发不带payload的条目更新时,会因为没执行绑定逻辑导致界面不刷新。
  • 可选优化
    你当前的列表是固定30条,不存在条目增删、移动的场景,可以在调用calculateDiff时显式关闭移动检测,减少差量计算的耗时:
    // 第二个参数传false,关闭条目移动检测
    DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DifUtil(newList, this.assetList), false);
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.03 04:27:04