我正在使用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
比较所有内容,尽管显示的列表未更新,但项目已经相等。如果该列表是参考,它将解释为什么适配器列表中的数据已经刷新,但是那我该如何解决呢?
最佳答案
我认为问题不是您加载新数据的方式,而是更新数据的方式。尽管您没有向我们展示触发项目更新的部分或实际更新的发生方式,但我猜很抱歉,如果我输入错了,您可能会像这样直接编辑列表元素:
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)
每次您想进行最小的更改时都创建一个全新的全新对象的想法一开始可能并不那么明显,但是这种被动的实现依赖于每个事件都独立于其他事件的假设。使您的数据类不可变或有效不可变将防止此问题。
为了避免这种错误,我总是想做些什么,我总是将数据类中的每个字段都定型为final。
@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
)
关于android - 如果只是项目的内容更改,PagedListAdapter不会更新列表,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54493764/