Android 上 LiveData 的并发问题
Concurrency issue with LiveData on Android
我正在尝试使用改造和 LiveData 操作从 API 中提取的数据。下面是我的代码
viewModel.getTransactions("withdrawals").observe(this, Observer {
if (it.getError() == null) {
dataAdapter = ArrayList(it.getTransaction()?.data)
if (dataAdapter.size == 0) {
// no withdrawal
withdrawSum = 0
} else {
it.getTransaction()?.data?.forEachIndexed { _, element ->
withdrawSum += Math.abs(element.attributes.amount)
}
}
} else {
// Error
}
})
viewModel.getTransactions("deposits").observe(this, Observer {
if(it.getError() == null){
dataAdapter = ArrayList(it.getTransaction()?.data)
if(dataAdapter.size == 0){
// no deposit
depositSum = 0
}else {
it.getTransaction()?.data?.forEachIndexed{ _, element ->
depositSum+=Math.abs(element.attributes.amount)
}
}
} else {
// Error
}
})
// difference will be 0 since deposit = 0 and withdrawal = 0
difference = deposit - withdrawal
我遇到的问题是这一行 difference = deposit - withdrawal
。这是立即调用的,而不是在进行减法之前等待 Retrofit 调用完成。我能做些什么来解决这个问题?一个可怕的解决方案是将存款代码嵌套在提款的 it.getError() == null
中,有没有更干净的解决方案?
我已经解决了这个问题。
val withdrawals = model.getTransactions("withdrawals")
val deposits = model.getTransactions("deposits")
zipLiveData(withdrawals, deposits).observe(this, Observer {
if(it.first.getError() == null){
dataAdapter = ArrayList(it.first.getTransaction()?.data)
if (dataAdapter.size == 0) {
// no withdrawal
withdrawSum = 0
} else {
it.first.getTransaction()?.data?.forEachIndexed { _, element ->
withdrawSum += Math.abs(element.attributes.amount)
}
}
} else {
// Error
}
if(it.second.getError() == null){
dataAdapter = ArrayList(it.second.getTransaction()?.data)
if (dataAdapter.size == 0) {
// no deposit
depositSum = 0
} else {
it.second.getTransaction()?.data?.forEachIndexed { _, element ->
depositSum += Math.abs(element.attributes.amount)
}
}
} else {
// Error
}
difference = depositSum - withdrawSum
})
函数zipLiveData
取自here
fun <A, B> zipLiveData(a: LiveData<A>, b: LiveData<B>): LiveData<Pair<A, B>> {
return MediatorLiveData<Pair<A, B>>().apply {
var lastA: A? = null
var lastB: B? = null
fun update() {
val localLastA = lastA
val localLastB = lastB
if (localLastA != null && localLastB != null)
this.value = Pair(localLastA, localLastB)
}
addSource(a) {
lastA = it
update()
}
addSource(b) {
lastB = it
update()
}
}
}
我正在尝试使用改造和 LiveData 操作从 API 中提取的数据。下面是我的代码
viewModel.getTransactions("withdrawals").observe(this, Observer {
if (it.getError() == null) {
dataAdapter = ArrayList(it.getTransaction()?.data)
if (dataAdapter.size == 0) {
// no withdrawal
withdrawSum = 0
} else {
it.getTransaction()?.data?.forEachIndexed { _, element ->
withdrawSum += Math.abs(element.attributes.amount)
}
}
} else {
// Error
}
})
viewModel.getTransactions("deposits").observe(this, Observer {
if(it.getError() == null){
dataAdapter = ArrayList(it.getTransaction()?.data)
if(dataAdapter.size == 0){
// no deposit
depositSum = 0
}else {
it.getTransaction()?.data?.forEachIndexed{ _, element ->
depositSum+=Math.abs(element.attributes.amount)
}
}
} else {
// Error
}
})
// difference will be 0 since deposit = 0 and withdrawal = 0
difference = deposit - withdrawal
我遇到的问题是这一行 difference = deposit - withdrawal
。这是立即调用的,而不是在进行减法之前等待 Retrofit 调用完成。我能做些什么来解决这个问题?一个可怕的解决方案是将存款代码嵌套在提款的 it.getError() == null
中,有没有更干净的解决方案?
我已经解决了这个问题。
val withdrawals = model.getTransactions("withdrawals")
val deposits = model.getTransactions("deposits")
zipLiveData(withdrawals, deposits).observe(this, Observer {
if(it.first.getError() == null){
dataAdapter = ArrayList(it.first.getTransaction()?.data)
if (dataAdapter.size == 0) {
// no withdrawal
withdrawSum = 0
} else {
it.first.getTransaction()?.data?.forEachIndexed { _, element ->
withdrawSum += Math.abs(element.attributes.amount)
}
}
} else {
// Error
}
if(it.second.getError() == null){
dataAdapter = ArrayList(it.second.getTransaction()?.data)
if (dataAdapter.size == 0) {
// no deposit
depositSum = 0
} else {
it.second.getTransaction()?.data?.forEachIndexed { _, element ->
depositSum += Math.abs(element.attributes.amount)
}
}
} else {
// Error
}
difference = depositSum - withdrawSum
})
函数zipLiveData
取自here
fun <A, B> zipLiveData(a: LiveData<A>, b: LiveData<B>): LiveData<Pair<A, B>> {
return MediatorLiveData<Pair<A, B>>().apply {
var lastA: A? = null
var lastB: B? = null
fun update() {
val localLastA = lastA
val localLastB = lastB
if (localLastA != null && localLastB != null)
this.value = Pair(localLastA, localLastB)
}
addSource(a) {
lastA = it
update()
}
addSource(b) {
lastB = it
update()
}
}
}