如果仅项目内容发生更改,PagedListAdapter 不会更新列表

2023-11-30

我正在使用 Room 和 Paging 库来显示类别。

我的实体:

@Entity(tableName = Database.Table.CATEGORIES)
data class Category(
    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = ID) var id: Long = 0,
    @ColumnInfo(name = NAME) var name: String = "",
    @ColumnInfo(name = ICON_ID) var iconId: Int = 0,
    @ColumnInfo(name = COLOR) @ColorInt var color: Int = DEFAULT_COLOR
)

My DAO:

@Query("SELECT * FROM $CATEGORIES")
fun getPagedCategories(): DataSource.Factory<Int, Category>

@Update
fun update(category: Category)

My Repo:

val pagedCategoriesList: LiveData<PagedList<Category>> = categoryDao.getPagedCategories().toLiveData(Config(CATEGORIES_LIST_PAGE_SIZE))

我的视图模型:

val pagedCategoriesList: LiveData<PagedList<Category>>
    get() = repository.pagedCategoriesList

我的适配器:

class CategoriesAdapter(val context: Context) : PagedListAdapter<Category, CategoriesAdapter.CategoryViewHolder>(CategoriesDiffCallback()) {

    //region Adapter

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CategoryViewHolder {
        return CategoryViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_category, parent, false))
    }

    override fun onBindViewHolder(holder: CategoryViewHolder, position: Int) {
        holder.bind(getItem(position)!!)
    }

    //endregion

    //region Methods

    fun getItemAt(position: Int): Category = getItem(position)!!

    //endregion

    inner class CategoryViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        private val iconHelper = IconHelper.getInstance(context)

        fun bind(category: Category) {
            with(itemView) {
                txvCategoryItemText.text = category.name
                imvCategoryItemIcon.setBackgroundColor(category.color)
                iconHelper.addLoadCallback {
                    imvCategoryItemIcon.setImageDrawable(iconHelper.getIcon(category.iconId).getDrawable(context))
                }
            }
        }
    }

    class CategoriesDiffCallback : DiffUtil.ItemCallback<Category>() {

        override fun areItemsTheSame(oldItem: Category, newItem: Category): Boolean {
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: Category, newItem: Category): Boolean {
            return oldItem == newItem
        }
    }
}

还有我的片段:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    categoryViewModel = ViewModelProviders.of(this).get(CategoryViewModel::class.java)

    adapter = CategoriesAdapter(requireContext())
    categoryViewModel.pagedCategoriesList.observe(this, Observer(adapter::submitList))
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    ViewCompat.setTooltipText(fabNewCategory, getString(R.string.NewCategory))

    with(mRecyclerView) {
        layoutManager = GridLayoutManager(requireContext(), 4)
        itemAnimator = DefaultItemAnimator()
        addItemDecoration(SpacesItemDecoration(resources.getDimensionPixelSize(R.dimen.card_default_spacing)))

        addOnItemTouchListener(OnItemTouchListener(requireContext(), this, this@CategoriesFragment))
    }

    mRecyclerView.adapter = adapter

    fabNewCategory.setOnClickListener(this)
}

插入、删除或加载类别时一切正常。 但是,当我更新单个实体的颜色或文本时,尽管正确调用了提交列表,但列表并未更新。

我调试了整个流程,发现了问题: 提交名单后,AsyncPagedListDiffer#submitList叫做。我比较了之前的列表(mPagedList in AsyncPagedListDiffer)和新列表(pagedListin AsyncPagedListDiffer#submitList)。我在那里编辑的项目是相同的,并且已经保存了新数据。所以DiffUtil比较所有内容,尽管显示的列表未更新,但项目已经相等。

如果该列表是一个参考,它可以解释为什么数据已经在适配器列表中刷新,但是我该如何解决这个问题呢?


我认为问题不在于加载新数据的方式,而在于更新数据。虽然您没有向我们展示触发项目更新的部分或实际更新如何发生,但我猜测,如果我错了,抱歉,您可能会直接编辑列表元素,如下所示:

category = adapter.getItemAt(/*item position*/)
category.name = "a new name"
category.color = 5
categoryViewModel.update(category)


相反,您应该创建一个新的Category对象而不是修改现有对象,如下所示:

prevCategory = adapter.getItemAt(/*put position*/) // Do not edit prevCategory!
newCategory = Category(id=prevCategory.id, name="a new name", color=5, iconId=0)
categoryViewModel.update(newCategory)


每次想要进行最小的更改时创建一个全新的对象的想法一开始可能并不那么明显,但这种反应式实现依赖于每个事件独立于其他事件的假设。使数据类不可变或实际上不可变可以防止此问题。

为了避免这种错误,我喜欢做的事情是,我总是将数据类中的每个字段都设置为最终字段。

@Entity(tableName = Database.Table.CATEGORIES)
data class Category(
    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = ID) val id: Long = 0,
    @ColumnInfo(name = NAME) val name: String = "",
    @ColumnInfo(name = ICON_ID) val iconId: Int = 0,
    @ColumnInfo(name = COLOR) @ColorInt val color: Int = DEFAULT_COLOR
)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如果仅项目内容发生更改,PagedListAdapter 不会更新列表 的相关文章

随机推荐

  • CurrentThread/ProcessThread 对象

    在 NET BCL中 有一个CurrentThread和一个ProcessThread对象 这些有什么区别呢 Thanks 这是设计 NET 2 0 时 SQL Server 项目的遗留问题 他们向 CLR 团队施压really很难打破 N
  • Android - 将资产复制到内部存储

    再会 我刚刚开始开发android 在我的应用程序中 我需要将资产文件夹中的项目复制到内部存储中 我在 SO 上搜索了很多 包括将其复制到外部存储的方法 如何将文件从 assets 文件夹复制到SD卡 这就是我想要实现的目标 我的内部存储中
  • 火星日食模糊

    使用 Eclipse Luna 几年后 我决定迁移到火星 我注意到当我用水平卷轴向右移动时它变得模糊 我正在笔记本电脑 Compaq 6710b 上使用 Ubuntu 14 04 有人可以帮我解决这个问题吗 这可能是由于月球上的 GTK 2
  • PHP DateTime 时区 - 构造函数与 Setter 方法

    使用 PHP 时DateTime类并尝试设置一个DateTimeZone根据我的设置方式 我得到不同的结果 使用DateTime construct或使用DateTime setTimezone method 这是一个例子 date 201
  • 属性映射未正确关联。为什么?

    EDIT 1虽然我知道对于这个特定的场景 以及其他类似的情况 我可以单独使用映射编辑器来正确迁移我的存储 以便持久存储中的值不会跳来跳去 但这并不是我当前问题的解决方案 而只是回避解决问题的根源 我热衷于坚持我的自定义迁移策略 因为这将使我
  • cx_Freeze 和 pyinstaller 出现导入错误

    我之前使用 pyinstaller 尝试将我的应用程序扭曲为可执行文件 但在执行时出现此错误 Traceback most recent call last File usr local lib python2 7 dist package
  • 我怎样才能做到颤振自动对焦但键盘关闭

    每当页面打开时 我希望出现光标 但我不需要键盘 有谁知道我该怎么做 TextField textCapitalization TextCapitalization sentences controller textEditingContro
  • 如何将 URL 编码为“可浏览”?

    我想知道是否有任何方法可以解析这样的 URL https www mysite com lot of unpleasant folders and my url with spaces others xls into https www m
  • 如何在 jquery ajax 的后期数据处理过程中设置加载图像?

    jquery ajax代码是 id btnpolls click function var valCheckedRadio input name data distributions checked val alert valChecked
  • 为什么从 main() 显式返回 0 被认为是好的做法? [复制]

    这个问题在这里已经有答案了 可能的重复 main 中的 return 语句与 exit 我刚刚读完第一章加速C 看起来是一本很棒的书 最后作者说 然而 明确地包含从 main 的返回是一个很好的做法 为什么这被认为是良好实践 在C99中 我
  • iOS 存档时未找到 Phonegap CDVViewController.h 文件

    我目前正在使用 Phonegap 2 0 在 XCode 中开发 iOS 应用程序 该应用程序在模拟器和测试设备上构建并运行良好 当我尝试存档应用程序以进行分发时 会出现问题 存档失败并显示以下消息 找不到 CDVViewControlle
  • 索引 jsonb 以进行字段的数字比较

    我定义了一个简单的表 create table resources id serial primary key fields jsonb 它包含带有键 从一个大集合中提取 和 1 到 100 之间的值的数据 例如 id fields
  • 使用强力查询通过数字字符串的最小长度从文本中提取数字

    Problem我的任务是整理一些非常混乱的包含文本和数字混合的数据 并希望使用强力查询将代码与数据分开 幸运的是 需要分隔的代码仅由数值组成 并且长度似乎为 7 个字符 假设为 6 个或更长 下面是我希望如何分离数据的示例 So Far 到
  • JavaScript 中的基本对象/函数链是如何工作的?

    我试图在脑海中直接理解 jQuery 风格的函数链接的原理 我的意思是 var e f1 test f2 f3 我已经找到一个可以工作的例子 而另一个却没有 我将在下面发布这些内容 我总是想学习一些东西如何工作的首要原理 这样我就可以在此基
  • 根据谷歌表格中的日期颜色代码交替行

    我想根据谷歌表格中的备用日期对行进行阴影处理 例如 第一行始终没有阴影 如下图所示 第 2 行和第 3 行中有一个新日期 2021 03 19 因此需要对它们进行阴影处理 之后 下一个日期 2021 01 01 不需要如此 依此类推 我最近
  • 使用单选按钮触发操作

    我正在做一个项目 我需要两个单选按钮来选择日期 一个单选按钮接受系统日期并打印 但当我选择另一个按钮时 我希望用户能够输入日期 基本上我想要一个文本字段当我单击第二个单选按钮时出现 我是 html 编码新手 所以请如果有人可以帮助我 我阅读
  • Hibernate:架构验证:缺少表

    我尝试从 MSSQL Server 2016 数据库中的现有表中读取数据 如果我验证 hbm2ddl auto gt 验证 我会收到异常 架构验证 缺少表 我将生成的 Hibernate SQL 代码 如果我从验证切换到更新 与我可以在 M
  • WPF 追加文本会严重阻塞 UI 线程,但 WinForms 不会?

    我最近将我的应用程序从 WinForms 转换为 WPF 我对大多数新功能感到满意 然而 我遇到了一个主要的障碍 当我不断地将文本附加到文本框时 UI 线程变得如此阻塞 以至于我除了看着它附加文本之外什么也做不了 我需要能够在选项卡控件中切
  • 使用 AVPlayer 将实时流的音轨静音

    我正在使用 AVPlayer 播放直播流 m3U8 文件 它使用 AVPlayer 可以完美播放 但我无法将其静音 我正在使用以下代码将音频静音 NSMutableArray allAudioParams NSMutableArray ar
  • 如果仅项目内容发生更改,PagedListAdapter 不会更新列表

    我正在使用 Room 和 Paging 库来显示类别 我的实体 Entity tableName Database Table CATEGORIES data class Category PrimaryKey autoGenerate t