【问题标题】:Android Leanback: How to update nested rows item in RowsSupportFragmentAndroid Leanback:如何更新 RowsSupportFragment 中的嵌套行项
【发布时间】:2023-01-22 00:22:27
【问题描述】:

大家好

我正在使用 androidTV 应用程序往后靠图书馆。

我应该显示每个类别都有自己的内容列表的类别列表。对于这种方法,leanback 提供行支持片段你可以在里面显示这种类型的用户界面。

这里我是使用Room + LiveData + Retrofit + Glide来执行和实现屏幕的,但是问题就在这里,api不会直接传递内容封面图片,所以开发者应该下载每个内容封面图片,存储它然后隐藏起来内容。

每件事都在工作,但在第一次,如果没有内容的封面图片,我会下载封面并存储它,但不会触发内容来获取和显示图像。使用通知项目范围已更改像这样的方法会闪烁并重置列表行,所以这不是一个好的解决方案。

这是我正在使用的 diffUtils,一个用于类别列表,一个用于每个内容列表。

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()
    }

}

正如我所说,我正在使用存储房间, 检索数据为实时数据并在我的片段中观察它们等等。我没有发布所有代码进行总结。

如果您有任何想法或类似的源代码,我将不胜感激。谢谢

编辑:12 月 2 日星期五 --- 添加更多详细信息

这是我的实时数据观察器,它保存并观察类别和数据的主要列表

private fun initViewModel() {
    
            categoriesViewModel.getCategoriesWithContent().observe(viewLifecycleOwner) { result ->
                val categoryModelList = MergedContentMapper().toCategoryModelList(result)
                initData(categoryModelList)
            }
    }

这是使用 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)
}

【问题讨论】:

  • 这里没有足够的信息可以提供帮助。您能否分享相关的 LiveData 可观察注册和片段代码?
  • 我添加了更多细节@kandroidj

标签: android kotlin android-tv leanback android-diffutils


【解决方案1】:

您的代码看起来是正确的,但它缺少您告诉Presenter 您的项目发生了什么变化的部分,因此它只能更改那条数据并且不需要重新绑定整个内容以避免闪烁。

首先,您需要将 DiffCallback.getChangePayload() 函数重写为如下内容:

override fun getChangePayload(oldItem: ListRow, newItem: ListRow): Any {
    return when {
        oldItem.headerItem.name != newItem.headerItem.name -> "change_title"
        else -> "change_items"
    }
}

这样,您的 ListRowPresenter 将收到有关 ListRowPresenter.onBindViewHolder() 重载中更改内容的信息,该重载接收有效载荷列表(由您的 DiffCallback 返回),如下所示:


override fun onBindViewHolder(
        viewHolder: Presenter.ViewHolder?,
        item: Any?,
        payloads: MutableList<Any>?
    ) {
    when {
        payloads == null || payloads.isEmpty() -> {
            // Your DiffCallback did not returned any information about what changed.
            super.onBindViewHolder(viewHolder, item, payloads)
        }
        "change_title" in payloads -> getRowViewHolder(viewHolder)?.let {
            headerPresenter.onBindViewHolder(it.headerViewHolder, item)
        }
        "change_items" in payloads -> {
            val newItems = ((item as? ListRow)?.adapter as? ArrayObjectAdapter)?.unmodifiableList<Item>()
            when (val listRowAdapter = (getRowViewHolder(viewHolder).row as? ListRow)?.adapter) {
                is ArrayObjectAdapter -> listRowAdapter.setItems(newItems, null)
                else -> super.onBindViewHolder(viewHolder, item, payloads)
            }
        }
        else -> {
            // If you don't know what changed just delegate to the super.
            super.onBindViewHolder(viewHolder, item, payloads)
        }
    }
}

根据您的需要自定义 DiffCallback.getChangePayload() 的实现。您可以返回此函数中的更改列表,并在您的ListRowPresenter.onBindViewHolder() 中处理所有更改。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-12-05
    • 2021-08-12
    • 1970-01-01
    • 2021-11-04
    • 1970-01-01
    • 2020-10-22
    • 1970-01-01
    相关资源
    最近更新 更多