Я выполняю рефакторинг репозитория с LiveData
объектами экземпляра в направлении Репозитория , который возвращает LiveData
из функций Репозитария в соответствии случшие практики из выступления на Саммите разработчиков Android в 2018 году, Развлечения с LiveData (Android Dev Summit '18) и сообщение в блоге разработчиков Android, LiveData за пределами ViewModel - Реактивные шаблоны с использованием Transformations и MediatorLiveData .
Наблюдаемый
При попытке вернуть объект MutableLiveData
в Репозиторий из метода, использующего функцию Observable.zip
, значение MutableLiveData
равноnull.
Ожидается
Возврат объекта MutableLiveData
из функции в Репозиторий метод с использованием функции Observable.zip
, которую можно наблюдать с помощью ViewModel и Фрагмент / Активность .
Оригинальный код
Шаги
- Хранилище 1045 * вызывается в
onCreate()
фрагмента 1048 *. getPrices()
извлекает последние данные о ценах с сервера. Для каждой части новых данных, извлекаемых с сервера, метод parsePriceData()
форматирует данные должным образом изаполняет экземпляр MutableLiveData
object graphLiveData
.
object PriceRepository {
var graphLiveData = MutableLiveData<HashMap<Exchange, PriceGraphData>>()
fun getPrices(isRealtime: Boolean, isOnCreateCall: Boolean, timeframe: Timeframe) {
listenerRegistration = contentEthBtcCollection
.orderBy(TIMESTAMP, Query.Direction.ASCENDING)
.whereGreaterThan(TIMESTAMP, getTimeframe(timeframe))
.addSnapshotListener(EventListener { value, error ->
error?.run {
Log.e(LOG_TAG, "Price Data EventListener Failed.", error)
return@EventListener
}
parsePriceData(value!!.documentChanges)
})
}
private fun parsePriceData(documentChanges: List<DocumentChange>) {
for (priceDataDocument in documentChanges) {
val priceData = priceDataDocument.document
.toObject(MaximumPercentPriceDifference::class.java)
compositeDisposable.add(zip(
generateGraphData(GRAPH_ONE, priceData.graphOneData).subscribeOn(io()),
generateGraphData(GRAPH_TWO, priceData.graphTwoData).subscribeOn(io()),
generateGraphData(GRAPH_THREE, priceData.graphThreeData).subscribeOn(io()),
generateGraphData(GRAPH_FOUR, priceData.graphFourData).subscribeOn(io()),
getFunction4())
.subscribeOn(io())
.observeOn(mainThread())
.subscribeWith(object : DisposableObserver<List<HashMap<Exchange, PriceGraphData>>>() {
override fun onNext(priceGraphDataList: List<HashMap<Exchange, PriceGraphData>>) {
priceGraphDataList.all {
// Working as expected.
graphLiveData.postValue(it)
true
}
}
override fun onError(e: Throwable) {
e.printStackTrace()
}
override fun onComplete() {
compositeDisposable.clear()
}
}))
}
}
}
Refactored Code
Шаги
Шаги 1-3 одинаковы, за исключениемна шаге 3 вместо сохранения значений в объекте экземпляра MutableLiveData
экземпляра значения сохраняются в объекте MutableLiveData
в методе.
object PriceRepository {
fun getPrices(isRealtime: Boolean, isOnCreateCall: Boolean, timeframe: Timeframe) {
contentEthBtcCollection
.orderBy(TIMESTAMP, Query.Direction.ASCENDING)
.whereGreaterThan(TIMESTAMP, getTimeframe(timeframe))
.get()
.addOnCompleteListener {
// This value is null. Thus the LiveData is not being returned properly in the 'parsePriceData' method.
val priceLiveData = parsePriceData(it.result!!.documentChanges)
}
}
}
private fun parsePriceData(documentChanges: List<DocumentChange>): LiveData<HashMap<Exchange, PriceGraphData>> {
val graphLiveData = MutableLiveData<HashMap<Exchange, PriceGraphData>>()
for (priceDataDocument in documentChanges) {
val priceData = priceDataDocument.document
.toObject(MaximumPercentPriceDifference::class.java)
//TODO: Refactor axis to use dates.
compositeDisposable.add(zip(
generateGraphData(GRAPH_ONE, priceData.graphOneData).subscribeOn(io()),
generateGraphData(GRAPH_TWO, priceData.graphTwoData).subscribeOn(io()),
generateGraphData(GRAPH_THREE, priceData.graphThreeData).subscribeOn(io()),
generateGraphData(GRAPH_FOUR, priceData.graphFourData).subscribeOn(io()),
getFunction4())
.subscribeOn(io())
.observeOn(mainThread())
.subscribeWith(object : DisposableObserver<List<HashMap<Exchange, PriceGraphData>>>() {
override fun onNext(priceGraphDataList: List<HashMap<Exchange, PriceGraphData>>) {
priceGraphDataList.all {
// Data returned here as expected, but LiveData object `graphLiveData.value` is returning null for the method.
graphLiveData.postValue(it)
true
}
}
override fun onError(e: Throwable) {
e.printStackTrace()
}
override fun onComplete() {
compositeDisposable.clear()
}
}))
}
return graphLiveData
}
}
Потенциальное решение
Проблема возникает из-за метода Observable.zip
, который возвращает данные асинхронно, а не синхронно.Замена логики Observable.zip
на MediatorLiveData
для обработки множественных вариаций графиков позволит вернуть объект LiveData
.Однако это требует рефакторинга серверной службы, чтобы упростить обработку данных для правильной работы с MediatorLiveData
.Поэтому в краткосрочной перспективе я ищу обходной путь с Observable.zip
.