我有一个项目,我想向用户显示多个项目(图像、文本、视频等)。我知道 RecyclerView 的多种视图类型是如何工作的。在我的项目中,我包含了大部分推荐的,Android Architecture Components
如Room
、Paging
、LiveData
等。
为了总结项目设计,我遵循了这个对我有很大帮助的codelab。Room
library + Paging
library with a提供了一种很好的BoundaryCallback
方式来实现离线缓存。将数据库视为事实的来源,并让Paging
图书馆在Recyclerview
需要时通过 a请求更多数据,这DataSource.Factory
在我看来是一种非常好的方法。
但是该项目的缺点是它们显示了整个架构组件的东西(Room
和Paging
with 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()
}
如您所见,我的模型类正在扩展Item
密封类。因此,我可以将Image
andText
类视为Item
s。适配器类看起来像这样:
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, parent, 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
使用超类访问属性Item
。我可以在这里做什么?
现在,我要去存储库类。您可能知道,存储库类首先负责从数据库中检索数据,因为在我的项目中,数据库是事实的来源。如果没有数据或需要更多数据,则分页库使用 BoundaryCallback 类从服务请求更多数据并将它们存储到数据库中。这是我的项目存储库类:
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
类。这些都是:
@Dao
interface ImageDao{
@Query("SELECT * from image_table")
fun getImages(): DataSource.Factory<Int, Image>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(images: List<Image>)
}
@Dao
interface TextDao{
@Query("SELECT * from text_table")
fun getTexts(): DataSource.Factory<Int, Text>
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertAll(texts: List<Text>)
}
那么,如何处理呢?
有人可以帮忙吗?