LR89
LR89

Reputation: 397

Filter RxJava Observable with other Observable

I'm using RxAndroid 2.0.1 with RxJava 2.0.6.

I have two observables: one returns Maybe<MyObject> based on some String (ID). When the optional object is returned, I have to call the second one that takes the MyObject instance and returns Single<Boolean> if object meets some conditions. Then I can do some further operations with the object instance.

My current implementation is as follows:

objectDAO.getById(objectId)
    .subscribe(
        myObject -> checkCondition(myObject),
        throwable -> /* Fallback */,
        () -> /* Fallback */
    );

private void checkCondition(final MyObject myObject) {
  otherDAO.checkCondition(myObject)
    .subscribe(
        isTrue -> {
          if (isTrue) {
            // yay! now I can do what I need with myObject instance
          } else {
            /* Fallback */
          }
        },
        throwable -> /* Fallback */
    );
}

Now I'm wondering how could I simplify my code. My ideas:

  1. Try to use zip - I can't because second Observable can't be subscribed until the first one returns the MyObject

  2. Try to use filter - Now the issue is that I need to use blocking get to call second observable. It will propably work, but looks like a code smell:

    objectDAO.getById(objectId)
      .filter(myObject ->
        otherDAO.checkCondition(myObject).blockingGet()
      )
      .subscribe(
          myObject -> checkCondition(myObject),
          throwable -> /* Fallback */,
          () -> /* Fallback */
      );
    
  3. Try to use flatMap - The second observable returns Boolean while I need to return the original object. Because of that I need to mape a code snippet with blockingGet and return original object or Maybe.empty()

Any suggestions how to do it in such a way that the code is "clean" (it's smaller and it's still clear what's happening inside)?

Upvotes: 5

Views: 2635

Answers (3)

Simon Basl&#233;
Simon Basl&#233;

Reputation: 28301

The RxJava2Extensions extra project by akarnokd has a filterAsync transformer (to be used with compose) that does just that, using a any Publisher<Boolean> ;)

Upvotes: 1

DruidKuma
DruidKuma

Reputation: 2480

I've come up with solution without passing Pairs with boolean values, in case anybody will face same problem. For example, if objectDAO.getById(objectId) returns Observable<T> and otherDAO.checkCondition(myObject) returns Single<Boolean>, we can handle filtering in such a way:

objectDAO.getById(objectId)
    .flatMap(myObject -> otherDAO
        .checkCondition(myObject)
        .toObservable()
        .filter(Boolean::booleanValue)
        .map(o -> myObject))
    .flatMapSingle(obj -> ...)

Unwanted objects will be resolved to Observable.empty and thus filtered, so that only needed objects will get to .flatMapSingle(obj -> ...)

Basically, same thing can be achieved with slightly easier to understand structure (though, I've found the first one a bit nicer aesthetically):

objectDAO.getById(objectId)
    .flatMap(myObject -> otherDAO
        .checkCondition(myObject)
        .flatMapObservable(isChecked -> isChecked ? Observable.just(myObject) : Observable.empty()))
        .flatMapSingle(obj -> ...)

Upvotes: 0

david.mihola
david.mihola

Reputation: 12982

One thing you could do:

objectDAO.getById(objectId)
    .flatMapSingle(myObject -> otherDAO
        .checkCondition(myObject)
        .map(isTrue -> Pair.create(myObject, isTrue))
    )

Then you have an Observable<Pair<MyObject, Boolean>> and can proceed however you want: subscribe directly and check the Boolean there, filter by the Boolean value, etc.

Upvotes: 5

Related Questions