【问题标题】:PagedListAdapter.submitList() Behaving Weird When Updating Existing ItemsPagedListAdapter.submitList() 更新现有项目时表现异常
【发布时间】:2018-11-21 07:51:59
【问题描述】:

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

当添加或删除项目时,会获取最新的数据集并将其传递给 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)
        })
    }
}

【问题讨论】:

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


【解决方案1】:

问题中缺少一些可以帮助提供更详细答案的内容。

例如。你的RecyclerView.Adapter 是什么样的?它是否扩展PagedListAdapter

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


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

如果我理解这个问题,您似乎只是 updating 一个项目,而不是删除或添加任何项目。 因此,DiffUtil.ItemCallbackareItemsTheSame 将始终返回true,因为旧列表和新列表的大小没有被修改。 这意味着,如果您更新了一个项目,您可能已经更新了它的内容,而不是从列表中删除它。

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

第二种方法areContentsTheSame 更有可能返回 false,因为您已经更新了项目的内容。

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

如果该模型不是Kotlin data class,那么您必须确保该类实现了compareTo 方法。如果不是,您将对象的内存地址与对象的实际内容进行比较。如果是这种情况,areContentsTheSame 方法将始终返回 true,因为对象的内存地址没有改变。

这些是一些调试技巧,因为如果不了解代码是如何实现的,很难提供更清晰的答案。

【讨论】:

  • 我刚刚更新了问题。 因此,areItemsTheSame 将返回 true,因为它们的 id 仍然相同 是的 areItemsTheSame 返回 true 并且两个模型的 id 也相同。但有趣的部分是为什么我看到 oldHistory 已更新??
  • 第二种方法 areContentsTheSame 更有可能返回 false,因为您已经更新了项目的内容 不,正如我所说的 oldHistorynewHistory 完全一样.而且oldHistory也更新了。
  • @NickNelson 不幸的是还没有。
【解决方案2】:

我遇到了类似的问题,但设法通过使用新对象更新现有项目而不是直接更新现有项目来解决它,正如这里的答案所建议的那样:

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-12
      • 1970-01-01
      相关资源
      最近更新 更多