I'm using the Room and Paging libraries to display categories.
My Entity:
@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))
My ViewModel:
val pagedCategoriesList: LiveData<PagedList<Category>>
get() = repository.pagedCategoriesList
My Adapter:
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
}
}
}
And my Fragment:
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)
}
Everything works when inserting, deleting or just loading categories. But when I'm updating a single entity's color or text, the list is not updated, though submit list is called correctly.
I debugged the whole process and found the problem:
After submitting the list, AsyncPagedListDiffer#submitList
is called. I compared the previous list (mPagedList
in AsyncPagedListDiffer
) and the new list (pagedList
in AsyncPagedListDiffer#submitList
). The items I edited there are equal and do already hold the new data. So DiffUtil
compares everything and the items are already equal though the displayed list is not updated.
If the list is a reference, it would explain why the data is already refreshed in the adapters list, but how do I solve the issue then?