Это не идеальный ответ, и я предполагаю, что есть лучшие способы (возможно, по крайней мере, с использованием преобразований ), но пока это работает.
Вместо того, чтобы загружать детей с помощью базы данных, я просто наблюдаю список LiveData и преобразую его, когда он изменяется для загрузки в адаптеры:
Во фрагменте / деятельности:
viewModel = ViewModelProviders.of(this).get(ItemViewModel::class.java)
viewModel.items.observe(this, Observer {items ->
val rootItem = items.filter { it.parent_id == null }
for (item in rootItem) //There should be only one root item but filter returns a list
item.populateChildren(items)
adapter.setItems(rootItem)
})
Сущности содержат метод populateChildren (subList: List), который рекурсивно заполняет поля @ Ignore'd в элементах, создавая древовидную структуру, начиная с rootItem и доступ к которой осуществляется через его дочерние элементы:
@Entity(
tableName = "items_table",
foreignKeys = [ForeignKey(entity = Item::class, parentColumns = ["id"], childColumns = ["parent_id"], onDelete = ForeignKey.CASCADE)])
data class Item(
@PrimaryKey(autoGenerate = true)
var id: Int,
var parent_id: Int?,
var name: String){
@Ignore var children: List<Item> = emptyList()
fun populateChildren(items: List<Item>){
children = items.filter { it.parent_id == this.id }
for (child in children)
child.populateChildren(items)
}
}
Этот метод просто делает то, что база данных сделала с помощью 'findChildItems ()', и сопоставляет parentID элементов в списке с идентификатором родителя.
Адаптер содержит метод setItems (), который пока использует notifyDataSetChanged () (не уверен, как правильно это обновить).
internal fun setItems(sItems: List<Item>) {
subList = sItems
notifyDataSetChanged()
}
Теперь в onBindViewHolder адаптера я передаю дочерние элементы новому переработчику. View:
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val viewItem = holder.itemView
val item : Item = subList[position]
when (holder.type) {
0 -> { // has children
// Update viewItem
// viewItem.[...] = item.[...]
viewItem.recyclerView.layoutManager =
LinearLayoutManager(context)
viewItem.recyclerView.adapter = ItemAdapter(item.children, context)
}
else -> { // no Children
val viewItem = holder.itemView
// Update viewItem
// viewItem.[...] = item.[...]
}
}
}
Список адаптеров также может быть установлен при создании экземпляра:
class ItemAdapter(var subList: List<Item>, val context: Context) : RecyclerView.Adapter<ItemViewHolder>() {