PagedListAdapter.submitList()在更新现有项目时表现奇怪

15

这个主题的小故事:应用程序只会在确认后使用对话框更新点击行的值。 在房间数据库中使用分页场景。

当添加或删除项目时,最新的数据集被获取并传递到submitList方法,然后所有更改都可以看到并正常工作。

问题从那里开始,如果更新现有项目,则再次正确获取最新数据集并传递给submitList,但是这次更改似乎没有出现。

当我调试DIFF_CALLBACK并在areItemsTheSame中捕获我的项目时,newHistory和oldHistory值相同! (怎么回事!)

submitList方法可能存在任何错误?

  • Room v. : 2.1.0-alpha02
  • Paging v. : 2.1.0-beta01

初始化后,observe从room中获取列表并传递给mHistoryAdapter.submitList(it)。 然后,如果我更新一个项目,观察将再次触发(我在参数it中看到了更新的值),并传递给submitList。

不幸的是,适配器不会更改...

    mResolvedAddressViewModel = ViewModelProviders.of(this).get(ResolvedAddressViewModel::class.java)
    mResolvedAddressViewModel.getAddresses(false).observe(this, Observer {
        mHistoryAdapter.submitList(it)
    })

所有的零件

型号

@Parcelize
@Entity
data class ResolvedAddress(
    @PrimaryKey var id: String = UUID.randomUUID().toString(),
    var requestedLat: Double = 0.0,
    var requestedLon: Double = 0.0,
    var requestedAddress: String = "",
    var lat: Double,
    var lon: Double,
    var address: String,
    var country: String,
    var countryCode: String,
    var city: String,
    var alias: String? = null,
    var favorite: Boolean = false,
    var provider: String? = null,
    var lastUseDate: Long = 0L) : Parcelable

适配器

class HistoryAdapter(var context: Context)
: PagedListAdapter<ResolvedAddress, HistoryItemHolder>(DIFF_CALLBACK) {

    companion object {
        private val DIFF_CALLBACK = object : DiffUtil.ItemCallback<ResolvedAddress>() {
            override fun areItemsTheSame(
                oldHistory: ResolvedAddress, newHistory: ResolvedAddress): Boolean {
                return oldHistory.id == newHistory.id
            }

            override fun areContentsTheSame(
                oldHistory: ResolvedAddress, newHistory: ResolvedAddress): Boolean {
                return oldHistory == newHistory
            }
        }
    }
}

片段

class HistoryFragment : Fragment() {
    private lateinit var mHistoryAdapter: HistoryAdapter
    private lateinit var mResolvedAddressViewModel: ResolvedAddressViewModel

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 
        savedInstanceState: Bundle?): View? {
        return inflater.inflate(R.layout.fragment_history, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        recyclerViewHistory.setHasFixedSize(true)
        recyclerViewHistory.layoutManager = LinearLayoutManager(activity)
        recyclerViewHistory.itemAnimator = DefaultItemAnimator()

        mHistoryAdapter = HistoryAdapter(context!!)
        recyclerViewHistory.adapter = mHistoryAdapter

        mResolvedAddressViewModel = ViewModelProviders.of(this)
        .get(ResolvedAddressViewModel::class.java)

        mResolvedAddressViewModel.getAddresses(false).observe(this, Observer {
            mHistoryAdapter.submitList(it)
        })
    }
}

3个回答

8
问题中缺少一些信息,这些信息可以帮助提供更详细的答案。
例如,你的RecyclerView.Adapter是什么样子的?它是否扩展了PagedListAdapter
你的模型类是什么样子的?它是Kotlin数据类吗?
为了提供答案,让我们假设这些未知因素是我们所期望的。
如果我理解问题正确,似乎你只是更新了一个项目,而没有删除或添加任何项目。因此,DiffUtil.ItemCallbackareItemsTheSame将始终返回true,因为旧列表和新列表在大小上没有被修改。这意味着,如果你更新了一个项目,你可能已经更新了它的内容,而不是从列表中删除它。
因此,areItemsTheSame将返回true,因为它们的id仍然相同。
更有可能的是,第二个方法areContentsTheSame将返回false,因为你已经更新了项目的内容。
如果你的模型类ResolvedAddress是Kotlin数据类,那么当比较从旧列表和新列表中更新的项目时,方法areContentsTheSame应该返回false。这应该触发你的适配器中的onBindViewHolder方法,以便你重新绑定具有更新数据的该项目。
如果该模型不是Kotlin数据类,那么你必须确保该类实现了compareTo方法。如果没有,你将比较对象的内存地址和对象的实际内容。如果是这种情况,方法areContentsTheSame将始终返回true,因为对象的内存地址没有改变。
这些都是一些调试提示,因为在没有更多关于代码如何实现的知识的情况下,提供更清晰的答案是困难的。

我刚刚更新了问题。因此,areItemsTheSame将返回true,因为它们的id仍然相同。是的,areItemsTheSame返回true,两个模型的id也相同。但有趣的部分是为什么我看到oldHistory被更新了? - blackkara
很可能第二种方法areContentsTheSame会返回false,因为您已经更新了项目的内容。不,正如我所说的,oldHistory和newHistory完全相同。而且oldHistory也已经更新了。 - blackkara
很抱歉,目前还没有。 - blackkara

2

1
问题出在submitList如何处理更改上。如果您传递对同一列表的引用,则不会显示更新,因为它确定是相同的数据源。在Kotlin中,如果您想要更新sourceList并将其传回submitList,可以按以下方式执行:
submitList(originalList.toList().toMutableList().let {
     it[index] = it[index].copy(property = newvalue) // To update a property on an item
     it.add(newItem) // To add a new item
     it.removeAt[index] // To remove an item
     // and so on....
     it
})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接