Объединение данных с нескольких репозиториев
Есть несколько репозиториев
ObjectRep - объекты
ObjTypeRep - описание типов объектов
TreeRep - дерево вложенностей
MotionRep - текущие параметры/состояние объекта (данных может и не быть)
На экране дерево объектов нужно показать join из всех этих репозиториев.
Как я думал это сделать:
1й вариант) Сделать
class ObjectsInteractor @Inject constructor(
private val objectRepository: ObjectRepository,
private val treeRepository: TreeRepository,
private val objectTypesRepository: ObjTypesRepository,
private val motionRepositry: MotionRepositry
){//.....}
и внутри этого интерактора все собирать.
Но это не выгодно, т.к. ObjectRepository возвращает List объектов и на каждый объект нужно дополнительно запросить ObjTypeRep и MotionRep (условно в цикле).
2й вариант) Сделать SuperObjectRepository из которого будет приходить собранный ответ. Выгода в том, что SuperObjectRepository будет получать данные из Room (Select join join) и выборка всех данных за одну операцию.. Но и есть минус, то, что получается какой-то монстр(выгода которого сразу исчезает если не будет Room с его joinами..).
Как быть? Нужно грамотное решение)
Используется:
- Rx
- Kotlin
- Room
- Retrofit
UP. Сделал по первому варианту вот так.
В интеракторе есть метод получения "Дерево". Единственное, я не на каждый объект по одному запрашиваю MotionRep, а запрашиваю списком и потом соединяю объекты с соответствующими motionState`ами.
Открыт к предложениям по оптимизации кода) p.s. по производительности в любом случае быстрее вариант №2.
fun getTreeObjects(parentFolderId: Long): Observable<TreeObject> {
return treeRepository.getTree(parentId = parentFolderId)
.flatMapObservable { tree ->
objectRepository.getObjects(parentFolderId)
.observeOn(Schedulers.io())
.flatMapObservable { objList ->
objList.map { it.id }.let { ids ->
motionRepositry.getMotionStates(objectIds = ids)
.defaultIfEmpty(emptyList()) //если нет данных то мутируем в пустой список
.map { motionState ->
objList.map { obj ->
Pair(
obj,
motionState.findLast { it.objectId == obj.id }
)
}
}
}
}
.observeOn(Schedulers.io())
.map { objects -> TreeObject(tree, objects) }
}
.observeOn(AndroidSchedulers.mainThread())
}
Ответы (1 шт):
Раз уж вы используете RX Java используйте ваш первый вариант. Но с одним нюансом. Создайте цепочку запросов с помощью метода combainLatest().
Observables.combineLatest(
objectRepository.getObjects(parentFolderId),
motionRepositry.getMotionStates(objectIds = ids),
::combineData
)
CombineData это ваш собественный метод в котором вы будете комбинировать ваши данные. Вы можете использовать и более двух аргументов в combineLatest()