具有多种视图类型的RecyclerView和具有边界回调的分页库

我有一个项目,我想向用户显示多个项目(图像,文本,视频等)。我知道RecyclerView的多种视图类型是如何工作的。 在我的项目中,我包含了大多数推荐的Android Architecture Components 例如RoomPagingLiveData

总结项目设计,我遵循了codelab,这对我有很大帮助。 Room库和带有Paging的{​​{1}}库提供了一种实现脱机缓存的好方法。在我看来,将数据库视为事实的来源,并让BoundaryCallback库通过Paging需要Recyclerview时需要更多数据,

但是project的缺点是它们显示了整个体系结构组件的内容(DataSource.FactoryRoomPaging)仅适用于一种项目类型。 但是我有多种视图类型,我无法处理。

下面,我向您展示项目中的代码段,以说明我被卡住的地方。

让我们从模型开始。假设我们有两种项目类型:图像和文本。

BoundaryCallback

如您所见,我的模型类正在扩展sealed class Item { @JsonClass(generateAdapter = true) @Entity(tableName = "image_table") data class Image( @PrimaryKey @Json(name = "id") val imageId: Long,val image: String ): Item() @JsonClass(generateAdapter = true) @Entity(tableName = "text_table") data class Text( @PrimaryKey @Json(name = "id") val textId: Long,val text:String ):Item() } 密封类。因此,我可以将ItemImage类视为Text。 适配器类如下所示:

Item

}

在这里,我面临的问题是private val ITEM_VIEW_TYPE_IMAGE = 0 private val ITEM_VIEW_TYPE_TEXT = 1 class ItemAdapter(): PagedListAdapter<Item,RecyclerView.ViewHolder>(ItemDiffCallback()) { override fun onBindViewHolder(holder: RecyclerView.ViewHolder,position: Int) { when (holder) { is TextItemViewHolder -> { val textItem = getItem(position) as Item.Text holder.bind(textItem) } is ImageItemViewHolder -> { val imageItem = getItem(position) as Item.Image holder.bind(imageItem) } } } override fun onCreateViewHolder(parent: ViewGroup,viewType: Int): RecyclerView.ViewHolder { return when (viewType) { ITEM_VIEW_TYPE_IMAGE -> ImageItemViewHolder.from(parent) ITEM_VIEW_TYPE_TEXT -> TextItemViewHolder.from(parent) else -> throw ClassCastException("Unknown viewType ${viewType}") } } override fun getItemViewType(position: Int): Int { return when (getItem(position)) { is Item.Image -> ITEM_VIEW_TYPE_IMAGE is Item.Text -> ITEM_VIEW_TYPE_TEXT } } class TextItemViewHolder private constructor(val binding: ListItemTextBinding): RecyclerView.ViewHolder(binding.root) { fun bind(item: Text) { binding.text = item binding.executePendingBindings() } companion object { fun from(parent: ViewGroup): TextItemViewHolder { val layoutInflater = LayoutInflater.from(parent.context) val binding = ListItemTextBinding.inflate(layoutInflater,parent,false) return TextItemViewHolder(binding) } } } class ImageItemViewHolder private constructor(val binding: ListItemImageBinding) : RecyclerView.ViewHolder(binding.root){ fun bind(item: Image) { binding.image = item binding.executePendingBindings() } companion object { fun from(parent: ViewGroup): ImageItemViewHolder { val layoutInflater = LayoutInflater.from(parent.context) val binding = ListItemImageBinding.inflate(layoutInflater,false) return ImageItemViewHolder(binding) } } } } class ItemDiffCallback : DiffUtil.ItemCallback<Item>() { // HERE,I have the problem that I can not access the id attribute override fun areItemsTheSame(oldItem: Item,newItem: Item): Boolean { return oldItem.id == newItem.id } override fun areContentsTheSame(oldItem: Item,newItem: Item): Boolean { return oldItem == newItem } } 类。在ItemDiffCallback方法中,我无法使用超类areItemsTheSame访问id属性。我在这里可以做什么?

现在,我要进入存储库类。您可能知道,存储库类负责首先从数据库中检索数据,因为在我的项目中数据库是事实的来源。如果没有数据或需要更多数据,则分页库使用BoundaryCallback类从服务中请求更多数据并将其存储到数据库中。这是我的商品存储库类:

Item

在这种情况下,我有一个问题,因为我有两个class ItemRepository(private val database: MyLimDatabase,private val service: ApiService) { fun getItems(): LiveData<PagedList<Item>> { val dataSourceFactory = ???????????? FROM WHICH TABLE I HAVE TO CHOOSE ???????? database.textDao.getTexts() or database.imageDao.getImages() val config = PagedList.Config.Builder() .setPageSize(30) // defines the number of items loaded at once from the DataSource .setInitialLoadSizeHint(50) // defines how many items to load when first load occurs .setPrefetchDistance(10) // defines how far from the edge of loaded content an access must be to trigger further loading .build() val itemBoundaryCallback = ItemBoundaryCallback(service,database) return LivePagedListBuilder(dataSourceFactory,config) .setBoundaryCallback(itemBoundaryCallback) .build() } } 类,所以我不知道如何初始化dataSourceFactory变量。这些是:

DAO

那么,如何处理呢?

有人可以帮忙吗?

rayest 回答:具有多种视图类型的RecyclerView和具有边界回调的分页库

为什么需要2张桌子?这两列相同。两种类型都使用一个公共数据类来保存另一个字段,以区分文本值代表的行,文本,图像uri,图像路径。使用IntDefenum可以轻松完成此操作。然后,您可以根据该新列返回一组可以相应处理的数据。

例如:

@IntDef(IMAGE,TEXT)
annotation class ItemType {
    companion object {
        const val IMAGE = 1
        const val TEXT = 2
    }
}

@Entity(tableName = "items_table")
data class Item(
    @PrimaryKey
    val id: Long,val itemData: String,@ItemType
    val type : Int)

@Dao
interface ItemsDao {
    @Query("SELECT * from items_table")
    fun getItems(): DataSource.Factory<Int,Item>

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun insertAll(itemss: List<Item>)
}

class ItemAdapter():
    PagedListAdapter<Item,RecyclerView.ViewHolder>(ItemDiffCallback()) {

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder,position: Int) {
        with(getItem(position)) {
            when (holder) {
                 // this could be simplified if using a common super view holder with a bind method that these subtypes inherit from
                 is TextItemViewHolder -> holder.bind(this)
                 is ImageItemViewHolder -> holder.bind(this)
            }
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup,viewType: Int): RecyclerView.ViewHolder {
        return when (viewType) {
            ITEM_VIEW_TYPE_IMAGE -> ImageItemViewHolder.from(parent)
            ITEM_VIEW_TYPE_TEXT -> TextItemViewHolder.from(parent)
            else -> throw ClassCastException("Unknown viewType ${viewType}")
        }
    }

    override fun getItemViewType(position: Int): Int {
        return when (getItem(position)?.type) {
            IMAGE -> ITEM_VIEW_TYPE_IMAGE
            TEXT -> ITEM_VIEW_TYPE_TEXT
            else -> -1
        }
    }
}

使用一个表,您当前面临的问题就不存在了。如果要从远程数据源/ api获取信息,则可以在插入之前轻松地将api数据类型转换为数据库的正确数据类型,无论如何我还是建议这样做。在不了解边界检查/服务细节的情况下,根据当前提供的代码和信息,这似乎是一种更好的方法。

本文链接:https://www.f2er.com/2833616.html

大家都在问