Hey Guys
I'm working on androidTV application using leanback library.
I should show list of categories that each category has it's own list of contents. For this approach leanback offered RowsSupportFragment that you can show this type of UI inside that.
Here I am using Room + LiveData + Retrofit + Glide to perform and implement the screen, but the issue is here, the api will not pass content cover images directly, so developer should download each content cover image, store it and then show covert over the content.
Every thing is working but at the first time, If there is no cover image for content, I will download the cover and store it, but content will not be triggered to get and show image. Using notifyItemRangeChanged and methods like this will blink and reset the list row so this is not a good solution.
This is my diffUtils that I'm using, one for category list, one for each contents list.
private val diffCallback = object : DiffCallback<CardListRow>() {
override fun areItemsTheSame(oldItem: CardListRow, newItem: CardListRow): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: CardListRow, newItem: CardListRow): Boolean {
return oldItem.cardRow.contents?.size == newItem.cardRow.contents?.size
}
}
private val contentDiffCallback = object : DiffCallback<ContentModel>() {
override fun areItemsTheSame(oldItem: ContentModel, newItem: ContentModel): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: ContentModel, newItem: ContentModel): Boolean {
return oldItem.hashCode() == newItem.hashCode()
}
}
As I said, for storage I'm using room, retrieving data as LiveData and observing them in my fragment and so on. I have not posted all the codes for summarization.
If you have any idea or similar source code, I would appreciate it. Thanks
Edit: Fri Dec 2 --- add some more details
This is my live-data observer that holds and observe main list on categories and datas
private fun initViewModel() {
categoriesViewModel.getCategoriesWithContent().observe(viewLifecycleOwner) { result ->
val categoryModelList = MergedContentMapper().toCategoryModelList(result)
initData(categoryModelList)
}
}
And this is the row creation scenario using ArrayObjectAdapter
private fun initData(categoryModelList: List<CategoryModel>) {
showLoading(false)
createRows(categoryModelList)
}
private fun createRows(categoryModelList: List<CategoryModel>) {
val rowItemsList: MutableList<CardListRow> = arrayListOf()
// create adapter for the whole fragment. It displays Rows.
categoryModelList.forEach { categoryModel ->
// create adapter for each row that can display CardView using CardPresenter
val cardListRow = createCardRow(categoryModel)
// add card list rows into list
rowItemsList.add(cardListRow)
}
// set item with diff util
rowsAdapter.setItems(rowItemsList, diffCallback)
}
private fun createCardRow(categoryModel: CategoryModel): CardListRow {
val contentList = categoryModel.contents ?: emptyList()
val cardListRowsAdapter = ArrayObjectAdapter(CardPresenterSelector(context, this))
cardListRowsAdapter.setItems(contentList, contentDiffCallback)
val headerItem = HeaderItem(categoryModel.title)
return CardListRow(headerItem, cardListRowsAdapter, categoryModel)
}
