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

时间:2018-11-21 07:52:00

标签: android android-architecture-components androidx android-paging

有关此主题的小故事:该应用仅在确认后使用对话框更新单击的行的值。在会议室数据库上使用分页方案。

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

问题从这里开始,如果更新了现有项目,则再次正确地获取了最新的数据集并将其传递给submitList,但是这次似乎没有变化。

当我调试DIFF_CALLBACK并在areItemsTheSame中捕获项目时,newHistoryoldHistory的值是相同的! (如何!)

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

  • 房间v .: 2.1.0-alpha02
  • 分页版:2.1.0-beta01

初始化后,observe从房间中获取列表并传递到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)
        })
    }
}

4 个答案:

答案 0 :(得分:6)

该问题遗漏了几处内容,可能有助于提供更详细的答案。

例如您的RecyclerView.Adapter是什么样的?它会扩展PagedListAdapter吗?

您的模型类是什么样的?它是Kotlin数据类吗?


为了提供答案,让我们假设那些未知数是我们所期望的。

如果我理解这个问题,似乎您只是updating个项目,而没有删除或添加任何项目。 因此,DiffUtil.ItemCallback的{​​{1}}将始终返回true,因为旧列表和新列表的大小均未修改。 意思是,如果您更新了一项,则可能是更新了其内容,而不是将其从列表中删除。

因此,areItemsTheSame将返回true,因为它们的ID仍然相同。

由于更新了项目的内容,第二种方法areItemsTheSame更有可能返回false。

如果您的模型类areContentsTheSame是Kotlin数据类,则在比较从旧列表和新列表更新的项目时,方法ResolvedAddress应该返回false。此时,这应该会触发适配器中的areContentsTheSame方法,以便您将该项目与更新的数据重新绑定。

如果该模型不是onBindViewHolder,则必须确保该类实现了Kotlin data class方法。如果不是,则将对象的内存地址与对象的实际内容进行比较。在这种情况下,由于对象的内存地址未更改,方法compareTo将始终返回true。

这些是一些调试技巧,因为在没有更多有关代码实现方式的知识的情况下很难提供更清晰的答案。

答案 1 :(得分:0)

我遇到了类似的问题,但设法通过使用新对象更新现有项目而不是直接更新现有项目来解决此问题,如以下答案所示:

https://stackoverflow.com/a/54505078/10923311

答案 2 :(得分:0)

仅当areItemsTheSame时才更新适配器数据集中的对象  或areContentsTheSame方法返回false。

您的areContentsTheSame方法应处理所有可能在运行时更新对象中变量的情况,如果任何变量发生更改,则应返回false,以反映在适配器数据集中,如下所示:

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

            // add this if you expect requestedLat to get updated 
            && oldHistory.requestedLat == newHistory.requestedLat

            // add this if you expect requestedLon to get updated 
            && oldHistory.requestedLon == newHistory.requestedLon

            // add this if you expect requestedAddress to get updated 
            && oldHistory.requestedAddress == newHistory.requestedAddress

            // add this if you expect lat to get updated 
            && oldHistory.lat == newHistory.lat


        }

答案 3 :(得分:0)

问题在于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
})