Android 具有复杂房间LiveData的嵌套Recyclerviews

Android 具有复杂房间LiveData的嵌套Recyclerviews,android,kotlin,android-recyclerview,android-livedata,Android,Kotlin,Android Recyclerview,Android Livedata,我有一个父对象集合,每个都有一个子对象集合。将它们称为ParentModels和ChildModels 在屏幕上,我想显示渲染父模型的RecyclerView,每个都包含渲染子模型的RecyclerView 为了避免仅仅因为一个ChildModel的一个属性发生了变化,而让god LiveData重新绘制所有内容,我打算将它们分开 我不知道如何用Recyclerview适配器和支架以及我需要的任何片段和视图模型来构造它。现在我有 class MyFragment: Fragment() {

我有一个父对象集合,每个都有一个子对象集合。将它们称为
ParentModel
s和
ChildModel
s

在屏幕上,我想显示渲染父模型的RecyclerView,每个都包含渲染子模型的RecyclerView

为了避免仅仅因为一个ChildModel的一个属性发生了变化,而让god LiveData重新绘制所有内容,我打算将它们分开

我不知道如何用Recyclerview适配器和支架以及我需要的任何片段和视图模型来构造它。现在我有

class MyFragment: Fragment() {
  private lateinit val mViewModel: FragmentViewModel
  // ...
  fun onViewCreated(/*...*/) {
    val parentAdapter = ParentAdapter()
    view.findViewById<RecyclerView>(/*...*/).apply {
      adapter = parentAdapter
      //...
    }
    viewModel.getParents().observe(this, Observer {
      parentAdapter.setParents(it)
    }
  }
}

class FragmentViewModel @Inject constructor(repository: RoomRepo): ViewModel() {
  mParents: LiveData<List<ParentModel>> = repository.getParents()
  fun getParents() = mParents
  //...
}

class ParentAdapter: RecyclerView.Adapter<ParentHolder>() {
  private lateinit var mParents: List<ParentModel>
  fun setParents(list: List<ParentModel>) {
    mParents = list
    notifyDataSetChanged()
  }
  override fun onCreateViewHolder(parent: ViewGroup, /*...*/) {
    return ParentHolder(LayoutInflater.from(parent.context).inflate(R.layout.parent, parent, false))
  }
  override fun onBindViewHolder(holder: ParentHolder, position: Int) {
    holder.bind(/*UNKNOWN*/)
  }
  // ...
  inner class ParentHolder(private val mView: View): RecyclerView.ViewHolder(mView) {
    fun bind(/*UNKNOWN*/) {
      // WHAT TO DO HERE???
    }
  }
}
我不假思索地写了一个ChildAdapter、ChildHolder和其他一些东西,因为我认为这将是一个微不足道的实现,但在这一点上,我的大脑被什么东西卡住了,我可能看不到明显的东西

我已经根据底层数据正确加载了第一个RecyclerView。但此父recyclerview还需要:

  • 基于单个parent.id获取子项
  • 为显示子项的单亲recyclerview项创建子recyclerview
  • Room从函数库返回LiveData>。getChildrenByParentId(id:Long)。这就是我工作的数据

    但是我在哪里获取这个,如何将它连接到属于父recyclerview的相关子recyclerview中

    我不想有一个上帝碎片 viewModel.getParents().observe(…){parentAdapter.update(it)}还必须执行某种类型的viewModel.getChildren().observe(…){parentAdapter.updateChildren(it)}

    因为这破坏了关注点的分离。在我看来,parent recyclerview中的每个项都应该有一个viewmodel,该viewmodel获取属于它的子项,然后创建一个recyclerview并使用ChildAdapter显示这些子项,但我似乎不知道在何处插入ChildFragment和ChildViewModel(其中包含
    repository.getChildrenByParentId
    )让这一切顺利进行


    我在网上找到的所有示例似乎都没有帮助,因为它们使用的是没有LiveData的人工示例和一个God片段/活动,它将所有内容都放在一个适配器中。

    我实际上有一个适配器可以渲染所有内容,使用
    DiffUtil
    (或其异步版本)类来确保我没有(我引用)“仅仅因为一个子模型的一个属性发生了变化,就重新绘制了所有内容”

    我将把构建(和提供)数据的复杂职责转移到您的存储库(或者,如果您更愿意,转移到您的ViewModel,作为一个或多个(我不知道您的模型看起来如何,所以我只是在想象)提供数据的存储库

    这将允许您向ui提供一个更精确的不可变列表,其中包含
    父级和子级
    ,而您的RecyclerView/适配器的职责突然变得更简单,显示它,并为每一行绑定正确的视图。您的ui突然变得更快,在主线程上做事情的时间更少,您甚至可以nit测试创建此列表的逻辑,完全独立于您的活动/片段

    我想象父母和孩子是这样的:

    class ParentChildren(父:父?、子:子?

    当父项不为null而子项为null时,绑定可能会膨胀一个视图。当子项不为null时,您知道它是子项(您也可以包括父项,这取决于您如何构造此数据)。问题在此处解决,您的适配器将如下所示

    class YourAdapter : ListAdapter<ParentChildren, RecyclerView.ViewHolder>(DiffUtilCallback()) {
    
    ...
    
    
    我将有一个抽象的基础来进一步简化适配器:

      internal abstract class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
            abstract fun bind(data: ParentChildren)
        }
    
    
    这可以让你拥有你的

        // I'm writing pseudo code here... keep it in mind
        internal class ParentViewHolder(itemView: View) : BaseViewHolder(itemView) {
            private val name: TextView = itemView.findViewById(R.id.item_text)
    
            override fun bind(data: ParentChildren) {
                name.text = parentChildren.parent?.name
            }
        }
    
        internal class ChildrenViewHolder(itemView: View) : BaseViewHolder(itemView) {
            private val name: TextView = itemView.findViewById(R.id.item_text)
    
            override fun bind(data: ParentChildren) {
                name.text = parentChildren.children?.name
            }
        }
    
    
    你明白了

    现在…
    ListAdapter
    有一个名为
    submitList(T)
    的方法,其中T是上述伪示例中适配器的类型
    ParentChildren

    这就是我要说的,现在您必须通过LiveData或任何您喜欢的架构来提供承载此适配器的活动或片段列表


    它可以是一个存储库,将其传递给viewModel中的可变LiveData,而viewModel公开了一个
    LiveData。这就是我最后做的。它工作得很好!不知道DiffUtilGood!:)祝你好运!
    
      internal abstract class BaseViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
            abstract fun bind(data: ParentChildren)
        }
    
    
        // I'm writing pseudo code here... keep it in mind
        internal class ParentViewHolder(itemView: View) : BaseViewHolder(itemView) {
            private val name: TextView = itemView.findViewById(R.id.item_text)
    
            override fun bind(data: ParentChildren) {
                name.text = parentChildren.parent?.name
            }
        }
    
        internal class ChildrenViewHolder(itemView: View) : BaseViewHolder(itemView) {
            private val name: TextView = itemView.findViewById(R.id.item_text)
    
            override fun bind(data: ParentChildren) {
                name.text = parentChildren.children?.name
            }
        }