在符合条件的情况下改变观察 - RxJava2

时间:2017-10-02 10:16:15

标签: android kotlin rx-java2 rx-kotlin2

使用RxJava2 RxKotlinRoom,我需要查询数据库以进行开放式搜索。这意味着我搜索包含名为closed且值为false的属性的搜索。找到寻线后,需要将查询切换到特定的寻线。

我有两种查询方法:

getOpenHunt(teamId:String): Flowable<List<Hunt>>
getHunt(huntId:String): Flowable<List<Hunt>>

它们都返回List,否则在没有找到寻线时查询会被卡住。

我的想法就像是

fun queryHunt(teamId:String):Flowable<Optional<Hunt>>{
   getOpenHunt(teamId)
      .map<Optional<Hunt>> {
                Optional.create(it.firstOrNull())
            }
      .switchToFlowableIf ( it is Optional.Some, getHunt(it.element().id)
}

//With switchToFlowableIf's being
fun <E:Any> switchToFlowableIf(condition: (E)->Boolean, newFlowable: Flowable<E>): Flowable<E>
//It should unsubscribe from getOpenHunt and subscribe to newFlowable

供参考,这是我的Optional课程

sealed class Optional<out T> {
class Some<out T>(val element: T) : Optional<T>()
object None : Optional<Nothing>()

fun element(): T? {
    return when (this) {
        is Optional.None -> null
        is Optional.Some -> element
    }
}

companion object {
    fun <T> create(element: T?): Optional<T> {
        return if (element != null) {
            Optional.Some(element)
        } else {
            Optional.None
        }
    }
}
}

RxJava2中是否已经内置了类似的方法?如果没有,你会如何实现它?

2 个答案:

答案 0 :(得分:1)

我通过查看onErrorResumeNext来解决这个问题。复制粘贴一些代码并修改为我的需要。我不认为这是完美的,但它确实是他的工作。如果您发现一些可能的错误,请发表评论。

public final class FlowableOnPredicateNext<T> extends AbstractFlowableWithUpstream<T, T> {

private final Predicate<? super T>                                  predicate;
private final Function<? super T, ? extends Publisher<? extends T>> next;

public FlowableOnPredicateNext(Flowable<T> source, Predicate<? super T> predicate,
                               Function<? super T, ? extends Publisher<? extends T>> next) {
    super(source);
    this.predicate = predicate;
    this.next = next;
}

@Override
protected void subscribeActual(Subscriber<? super T> s) {
    OnPredicateNextSubscriber<T> parent = new OnPredicateNextSubscriber<>(s, next, predicate);
    s.onSubscribe(parent.arbiter);
    source.subscribe(parent);
}

static final class OnPredicateNextSubscriber<T> implements FlowableSubscriber<T> {

    private final Subscriber<? super T>                                 actual;
    private final Predicate<? super T>                                  predicate;
    private final SubscriptionArbiter                                   arbiter;
    private final Function<? super T, ? extends Publisher<? extends T>> nextSupplier;
    private boolean switched = false;

    OnPredicateNextSubscriber(Subscriber<? super T> actual,
                              Function<? super T, ? extends Publisher<? extends T>>
                                      nextSupplier, Predicate<? super T> predicate) {
        this.actual = actual;
        this.predicate = predicate;
        this.nextSupplier = nextSupplier;
        this.arbiter = new SubscriptionArbiter();
    }

    @Override
    public void onSubscribe(Subscription s) {
        arbiter.setSubscription(s);
    }

    @Override
    public void onNext(T t) {
        try {
            if (!switched && predicate.test(t)) {
                Publisher<? extends T> p;
                p = nextSupplier.apply(t);
                p.subscribe(this);
                switched = true;
            } else {
                actual.onNext(t);
            }
        } catch (Exception e) {
            actual.onError(e);
        }
    }

    @Override
    public void onError(Throwable t) {
        actual.onError(t);
    }

    @Override
    public void onComplete() {
        actual.onComplete();
    }
}
}

使用Kotlin我写了一个扩展函数:

@CheckReturnValue
@BackpressureSupport(BackpressureKind.FULL)
@SchedulerSupport(SchedulerSupport.NONE)
fun <E, T : Flowable<E>> T.onPredicateResumeNext(predicate: Predicate<E>, resumeFunction: io.reactivex.functions.Function<E, Publisher<E>>): Flowable<E> {
return RxJavaPlugins.onAssembly<E>(FlowableOnPredicateNext<E>(this,
                                                              predicate,
                                                              resumeFunction
                                                             ))
}

我现在正在使用它:

override fun getOpenHunt(teamId: String): Flowable<Optional<Hunt>> {
    return created().getOpenHunt(teamId)
            .map {
                Optional.create(it.firstOrNull())
            }
            .onPredicateResumeNext(predicate = Predicate { it.element() != null },
                                   resumeFunction = Function {
                                       created()
                                               .getHunt(it.element()!!.id)
                                               .map<Optional<Hunt>> {
                                                   Optional.create(it.firstOrNull())
                                               }
                                   })
}

答案 1 :(得分:0)

我会通过重复使用你的方法来做到这一点:

getOpenHunt(teamId:String): Flowable<List<Hunt>>
getHunt(huntId:String): Flowable<List<Hunt>>

getOpenHunt(yourId) // return your Flowable<List<Hunt>>
.flatMapIterable { it } // get each result of open hunts
.flatMapMaybe {  getHunt(it.id) } // querie each result 
.toList() // back to a Maybe/Single<List<Hunt>>
.toFlowable() // back to a Flowable else it wont emit more data
.subscribeBy(onNext = { /** process your results **/ },
             onError = { /** process if no results found **/  }
            )

这意味着如果有符合条件的条目,则查询数据库。然后它得到结果,将其拆分为单个项目,使用您的结果运行多个查询。如果找到结果,则会将其转换回Single<List<Hunt>>。由于您希望继续订阅,因此需要使用.toFlowable()

将其转换回Flowable

顺便说一下,更改意味着返回值会更改,但在您的情况下,它会相同List<Hunt>

整个流程对我来说没有任何意义,因为你也可以通过getOpenHunt得到结果并迭代它。