liangjingkanji / BRV

[使用文档] Android 快速构建 RecyclerView, 比 BRVAH 更简单强大
http://liangjingkanji.github.io/BRV/
MIT License
2.51k stars 317 forks source link

diff和payload同时使用的时候,BindingViewHolder里面还是老数据 #321

Closed pyj831 closed 1 year ago

pyj831 commented 1 year ago

问题描述

onPayload执行以后,BindingViewHolder不会调用bind,数据还是老的,这个方法又是internal修饰的,导致列表刷新不了

期望行为

如何复现

任何业务相关问题没有fork仓库复现问题一律无法解决, 凭空猜测只会让问题晦涩难懂, 大量耽误项目维护时间

截图

异常堆栈信息或者手机截图/视频(拖拽到输入框即可上传)

版本

liangjingkanji commented 1 year ago
  1. 如果执行BindingViewHolder.bind就不是局部更新了而是完全更新了
  2. 你可以重写BindingAdapter来实现全部调用
public void onBindViewHolder(@NonNull VH holder, int position,
        @NonNull List<Object> payloads) {
    onBindViewHolder(holder, position);
}
pyj831 commented 1 year ago

之前单独用payload的时候是直接更新了数据,因为是同一个对象,所以models和bindviewholder里面的都变了,然后再局部刷新。现在用diff+payload的时候,models变了,但是bindviewholder的数据不会自己更新,导致直接用getmodel取到的还是老数据,想要一个单独更新BindingViewHolder里面数据的入口,并不需要bind的完整功能。我现在是在payload里面拿models的数据去进行的局部刷新,凑合在用

liangjingkanji commented 1 year ago
  1. 如果你使用diffUtils工具去更新, 他会自动调用notify**方法

  2. 如果你手动调用notify**()去局部更新, 那么你更新之前就需要自己先更新models数据集合

  3. 任何更新都要求先更新models, 数据集合都不更新你就调用局部更新方法当然会有问题, 即使调用bind()也是不会改变数据集合没有更新问题, 也可以在onPayload里面更新原有的model, 使用getModel()然后为其对象赋值新数据(局部更新不会改变model对象引用只是改变其中部分属性)

另外你想要调用bind()且觉得重写BindingAdapter麻烦可以使用以下代码, 一样效果, 很简单的查看源码就能知道

onPayload { 
    onBindViewHolder(this, layoutPosition)
}
pyj831 commented 1 year ago

image 我看这个方法里面更新了_data,然后在自动调用notify的时候,BindingAdapter里的data没有更新

liangjingkanji commented 1 year ago

BindingAdapter里的data是什么?

pyj831 commented 1 year ago

打错了BindingViewHolder这个里面的_data

pyj831 commented 1 year ago

然后我直接调用getModel取到的就是老数据,新数据得自己从adapter里的_data拿

liangjingkanji commented 1 year ago

以下我说的内容和BRV框架本身设计无关

如果setDiffModels()对比数据后触发局部更新, 无法做到刷新BindingViewHolder._data数据

因为局部刷新本身不会返回model而是返回增量数据(ItemDifferCallback.getChangePayload()返回值), 这可以是任何类型的对象

你如果需要更新BindingViewHolder._data数据请自己手动完成

例如:

binding.rv.dividerSpace(10.dp).setup {
    addType<GameModel.Data>(R.layout.item_game)
    onPayload {
        val model = getModel<GameModel.Data>()
        model.img = it[0] as String // 例如这里的增量数据直接是一个图片地址字符串
    }
}

如果对DiffUtils不够熟悉我也不推荐使用setDiffModels(), 这并不是一个万能方法, 甚至很多时候比直接models = newData麻烦得多

你的项目可能并不需要Diff, 也许你需要的是DataBinding的自动更新View功能

pyj831 commented 1 year ago

抱歉,因为item里面东西有点多,payload里面我没有传具体的数据,传的是哪些view需要更新,所以才想着修改viewholder里的数据

liangjingkanji commented 1 year ago

那你完全不需要增量更新, 直接notifyItemDataChanged(position)就行了(第2个参数不要传)

没特别需求别用setDiffModels()

pyj831 commented 1 year ago

之前的老哥在那里用的room+livedata,只要数据有变动,扔一个list出来,不用diff的话,每次都是整体刷新,所以我才想diff+payload

liangjingkanji commented 1 year ago

对于这种没有规律的数据集合变更的确正是setDiffModels的最佳使用场景