我有一个Fragment
,其中包含动态数量的自定义视图,包含EditText
和Button
。我所做的是,每次用户在EditText
中输入价格并点击Button
时,我都会通过ViewModel发出API请求,而我的Fragment
会观察LiveData
} ViewModel
。
到目前为止,当我使用第一个自定义视图时这么好。问题出现在第二个(和第三个)上,因为onChanged()
方法显然被调用,即使数据没有改变,第二个和第三个自定义视图也在监听这些数据,因此它们会在它们不是触发数据更改的那些(它们从第一个接收数据变化)。
当用户点击Button
时,我观察并获取价格的方式是:
val observer = Observer<NetworkViewState> { networkViewState ->
processResponse(networkViewState, moneySpent, coin, date)
}
boardingHistoricalPriceViewModel.coinDayAveragePrice.observe(this, observer)
boardingHistoricalPriceViewModel.getDayAveragePrice(coin.symbol,
addedCoinDatePriceView.selectedSpinnerItem, dateInMillis)
正在发生的事情是当第二个自定义视图触发API请求时调用方法processResponse
,但我收到的结果是coinDayAveragePrice
在API响应到达之前的结果(这个是第一个自定义视图的第一个API响应到达后的值。
这是我的ViewModel
:
val coinDayAveragePrice: MutableLiveData<NetworkViewState> = MutableLiveData()
fun getDayAveragePrice(symbol: String, currency: String, dateInMillis: Long) {
coinRepository
.getDayAverage(symbol, currency, "MidHighLow", dateInMillis)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe { coinDayAveragePrice.postValue(NetworkViewState.Loading()) }
.subscribeBy(onSuccess = {
coinDayAveragePrice.postValue(NetworkViewState.Success(it))
}, onError = { throwable ->
coinDayAveragePrice.postValue(NetworkViewState.Error(throwable.localizedMessage))
})
}
NetworkViewState
只是一个sealed class
,意味着作为API请求响应的包装器:
sealed class NetworkViewState {
class Loading : NetworkViewState()
class Success<out T>(val item: T) : NetworkViewState()
class Error(val errorMessage: String?) : NetworkViewState()
}
我还尝试取消订阅或将coinDayAveragePrice
设置为null,但我仍遇到同样的问题。
提前多多感谢!
答案 0 :(得分:0)
所以,如果没有看到你的ViewModel
,很难确切地知道问题是什么,但我认为这是我在评论中指出的内容。在这种情况下,一种解决方案是使用不同类型的LiveData
。我从博客文章中得到了这个基本想法(不记得链接: - /),但这里是班级:
private const val TAG = "SingleLiveData"
/**
* A lifecycle-aware observable that sends only new updates after subscription, used for events like
* navigation and Snackbar messages.
*
* This avoids a common problem with events: on configuration change (like rotation) an update
* can be emitted if the observer is active. This LiveData only calls the observable if there's an
* explicit call to setValue() or call().
*
* Note that only one observer is going to be notified of changes.
*/
open class SingleLiveData<T> : MutableLiveData<T>() {
private val pending = AtomicBoolean(false)
@MainThread
override fun observe(owner: LifecycleOwner, observer: Observer<T>) {
if (hasActiveObservers()) {
Logger.w(TAG, "Multiple observers registered but only one will be notified of changes.")
}
// Observe the internal MutableLiveData
super.observe(owner, wrapObserver(observer))
}
@MainThread
override fun observeForever(observer: Observer<T>) {
if (hasActiveObservers()) {
Logger.w(TAG, "Multiple observers registered but only one will be notified of changes.")
}
super.observeForever(wrapObserver(observer))
}
private fun wrapObserver(observer: Observer<T>): Observer<T> {
return Observer {
if (pending.compareAndSet(true, false)) {
observer.onChanged(it)
}
}
}
@MainThread
override fun setValue(t: T?) {
pending.set(true)
super.setValue(t)
}
/**
* Used for cases where T is Void, to make calls cleaner.
*/
@MainThread
fun call() {
value = null
}
}
显然,这方面的一个问题是它不允许多个观察者使用相同的实时数据。但是,如果您需要,希望本课程能为您提供一些想法。