使用 livedata 压缩 4 个或更多异步调用
Zip 4 or more async calls using livedata
有没有可能使用 livedata 运行 多个并行异步调用的方法?
假设我有 4 个异步调用。我想等到一切都完成,然后相应地使用所有 4 个调用的结果。
我能想到的一种方法是
public class MakeParallel {
private final CountDownLatch countDown = new CountDownLatch(4);
public void firstCall() {
Transformation.map(makeFirstCall(), input -> {
if(input.isSuccessful()) {
countDownLatch.countDown();
checkResult();
}
return input;
}
}
public void secondCall() {
Transformation.map(makeSecondCall(), input -> {
if(input.isSuccessful()) {
countDownLatch.countDown();
checkResult();
}
return input;
}
}
void checkResult() {
if(countDownLatch.getCount == 0) {
// Result is ready
} else {
// Something has error
}
}
}
有没有更好的办法解决这种情况??
所以诀窍是使用 MediatorLiveData 并让它观察每个 LiveData 对象并将更改压缩到某种集合中。
public static LiveData<ArrayList<Object>> zipLiveData(LiveData<Object>... liveItems){
final ArrayList<Object> zippedObjects = new ArrayList<>();
final MediatorLiveData<ArrayList<Object>> mediator = new MediatorLiveData<>();
for(LiveData<Object> item: liveItems){
mediator.addSource(item, new Observer<Object>() {
@Override
public void onChanged(@Nullable Object o) {
if(!zippedObjects.contains(o)){
zippedObjects.add(o);
}
mediator.setValue(zippedObjects);
}
});
}
return mediator;
}
或者在 Kotlin 中:
fun zipLiveData(vararg liveItems: LiveData<*>): LiveData<ArrayList<Any>> {
return MediatorLiveData<ArrayList<Any>>().apply {
val zippedObjects = ArrayList<Any>()
liveItems.forEach {
addSource(it, { item ->
if (! zippedObjects.contains(item as Any)) {
zippedObjects.add(item)
}
value = zippedObjects
})
}
}}
此解决方案没有类型安全。随意定制您的需求!
这将允许您将 3 个 liveData 压缩为一个。如果您需要超过 3 个,就很容易知道该怎么做。
fun <A,B,C> zippedLiveData(a: LiveData<A>, b: LiveData<B>, c: LiveData<C>): LiveData<Pair<A, Pair<B,C>>> {
return MediatorLiveData<Pair<A, Pair<B,C>>>().apply {
var lastA: A? = null
var lastB: B? = null
var lastC: C? = null
fun update() {
val localLastA = lastA
val localLastB = lastB
val localLastC = lastC
if (localLastA != null && localLastB != null && localLastC != null)
this.value = Pair(localLastA, Pair(localLastB, localLastC))
}
addSource(a) {
lastA = it
update()
}
addSource(b) {
lastB = it
update()
}
addSource(c) {
lastC = it
update()
}
}
}
有没有可能使用 livedata 运行 多个并行异步调用的方法?
假设我有 4 个异步调用。我想等到一切都完成,然后相应地使用所有 4 个调用的结果。
我能想到的一种方法是
public class MakeParallel {
private final CountDownLatch countDown = new CountDownLatch(4);
public void firstCall() {
Transformation.map(makeFirstCall(), input -> {
if(input.isSuccessful()) {
countDownLatch.countDown();
checkResult();
}
return input;
}
}
public void secondCall() {
Transformation.map(makeSecondCall(), input -> {
if(input.isSuccessful()) {
countDownLatch.countDown();
checkResult();
}
return input;
}
}
void checkResult() {
if(countDownLatch.getCount == 0) {
// Result is ready
} else {
// Something has error
}
}
}
有没有更好的办法解决这种情况??
所以诀窍是使用 MediatorLiveData 并让它观察每个 LiveData 对象并将更改压缩到某种集合中。
public static LiveData<ArrayList<Object>> zipLiveData(LiveData<Object>... liveItems){
final ArrayList<Object> zippedObjects = new ArrayList<>();
final MediatorLiveData<ArrayList<Object>> mediator = new MediatorLiveData<>();
for(LiveData<Object> item: liveItems){
mediator.addSource(item, new Observer<Object>() {
@Override
public void onChanged(@Nullable Object o) {
if(!zippedObjects.contains(o)){
zippedObjects.add(o);
}
mediator.setValue(zippedObjects);
}
});
}
return mediator;
}
或者在 Kotlin 中:
fun zipLiveData(vararg liveItems: LiveData<*>): LiveData<ArrayList<Any>> {
return MediatorLiveData<ArrayList<Any>>().apply {
val zippedObjects = ArrayList<Any>()
liveItems.forEach {
addSource(it, { item ->
if (! zippedObjects.contains(item as Any)) {
zippedObjects.add(item)
}
value = zippedObjects
})
}
}}
此解决方案没有类型安全。随意定制您的需求!
这将允许您将 3 个 liveData 压缩为一个。如果您需要超过 3 个,就很容易知道该怎么做。
fun <A,B,C> zippedLiveData(a: LiveData<A>, b: LiveData<B>, c: LiveData<C>): LiveData<Pair<A, Pair<B,C>>> {
return MediatorLiveData<Pair<A, Pair<B,C>>>().apply {
var lastA: A? = null
var lastB: B? = null
var lastC: C? = null
fun update() {
val localLastA = lastA
val localLastB = lastB
val localLastC = lastC
if (localLastA != null && localLastB != null && localLastC != null)
this.value = Pair(localLastA, Pair(localLastB, localLastC))
}
addSource(a) {
lastA = it
update()
}
addSource(b) {
lastB = it
update()
}
addSource(c) {
lastC = it
update()
}
}
}