如果只是项目的内容更改,PagedListAdapter不会更新列表

时间:2019-02-02 14:00:37

标签: android kotlin android-recyclerview android-adapter android-paging

我正在使用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
)

我的DAO:

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

@Update
fun update(category: Category)

我的仓库:

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

我的ViewModel:

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中的{AsyncPagedListDiffer)和新列表(pagedList中的AsyncPagedListDiffer#submitList)。我在那里编辑的项目相等,并且已经保存了新数据。因此DiffUtil比较所有内容,尽管显示的列表未更新,但项目已经相等。

如果该列表是参考,它将说明为什么适配器列表中的数据已经刷新,但是那我该如何解决呢?

3 个答案:

答案 0 :(得分:2)

我认为问题不是您加载新数据的方式,而是更新数据的方式。尽管您尚未向我们展示触发项目更新的部分或实际更新的发生方式,但我猜很抱歉,如果我错了,您可能会像这样直接编辑列表元素:

softmax


相反,您应该创建一个新的category = adapter.getItemAt(/*item position*/) category.name = "a new name" category.color = 5 categoryViewModel.update(category) 对象,而不是像这样修改现有对象:

Category


每次想进行最小的更改时都创建一个全新的全新对象的想法一开始可能并不那么明显,但是不变性是 Functional Reactive Programming 的关键部分,在很多情况下反应组件的数量依赖于所处理数据的不变性。

为了避免这种错误,我总是想做些什么,我总是将数据类中的每个字段都设为final。

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)

答案 1 :(得分:0)

除非您显示包含DiffUtill.itemcallaback的Dao和pagedlistadapter类,否则任何人都无法回答您的问题。 我向您展示了一些可能会有所帮助的代码。

  1. 您必须像这样在DAO界面中实现更新:

    @更新 有趣的updateUsers(data:MyData)

如果之后使用此方法,则可以像下面那样检查diffcall:

app.get("/users/:next", (req, res) => res.json({message: "hello world 2 " + req.params.next })));

答案 2 :(得分:0)

我已经在PagedListAdapter上进行了RnD,并使用Room数据库进行了自定义分页。 单击here,您将找到我的实现。希望对您有帮助。

谢谢。