pushtorefresh / storio

Reactive API for SQLiteDatabase and ContentResolver.
Apache License 2.0
2.55k stars 182 forks source link

onComplete not getting called when a flatMapped inner Observable has completed #523

Closed waynesford closed 9 years ago

waynesford commented 9 years ago

I've taken the example inside TweetsFragment from the sample app and modified it slightly to show what I mean. inner.doOnCompleted will log successfully, but outer.onComplete() does not get called:

final Subscription subscription = storIOSQLite
        .get()
        .listOfObjects(Tweet.class)
        .withQuery(TweetsTable.QUERY_ALL)
        .prepare()
        .createObservable() // it will be subscribed to changes in tweets table!
        .delay(1, SECONDS) // for better User Experience :) Actually, StorIO is so fast that we need to delay emissions (it's a joke, or not)
        .flatMap(new Func1<List<Tweet>, Observable<List<Tweet>>>() {
            @Override
            public Observable<List<Tweet>> call(List<Tweet> tweets) {
                List<Tweet> list = new ArrayList<Tweet>();
                list.add(Tweet.newTweet("Superman", "saving the day"));
                return Observable.just(list)
                        .doOnNext(new Action1<List<Tweet>>() {
                            @Override
                            public void call(List<Tweet> tweets) {
                                Timber.d("inner.doOnNext");
                            }
                        })
                        .doOnCompleted(new Action0() {
                            @Override
                            public void call() {
                                Timber.d("inner.doOnCompleted");
                            }
                        });
            }
        })
        .observeOn(mainThread())
        .subscribe(new Action1<List<Tweet>>() {
            @Override
            public void call(List<Tweet> tweets) {
                Timber.d("outer.onNext()");
                // Remember: subscriber will automatically receive updates
                // Of tables from Query (tweets table in our case)
                // This makes your code really Reactive and nice!

                // We guarantee, that list of objects will never be null (also we use @NonNull/@Nullable)
                // So you just need to check if it's empty or not
                if (tweets.isEmpty()) {
                    uiStateController.setUiStateEmpty();
                    tweetsAdapter.setTweets(null);
                } else {
                    uiStateController.setUiStateContent();
                    tweetsAdapter.setTweets(tweets);
                }
            }
        }, new Action1<Throwable>() {
            @Override
            public void call(Throwable throwable) {
                // In cases when you are not sure that query will be successful
                // You can prevent crash of the application via error handler
                Timber.e(throwable, "outer.onError()");
                uiStateController.setUiStateError();
                tweetsAdapter.setTweets(null);
            }
        }, new Action0() {
            @Override
            public void call() {
                Timber.d("outer.onComplete()");
            }
        });
artem-zinnatullin commented 9 years ago

Because Get operation in StorIO returns infinitive Obserbable!

Observable from Get operation observes changes in the DB/ContentProvider, so it can be used for constantly updates of the lists and other kinds of UI, just like Loaders API!

If you want to get result via Rx once, please use take(1) or first() :)

@waynesford feel free to ask questions if you have them! BTW we would like to keep GitHub issues for feature requests and bug reports if it's possible, you can ask questions about usage patterns of StorIO on StackOverflow with storio tag (we watch this tag) :)

waynesford commented 9 years ago

thanks @artem-zinnatullin, it's good to know you guys are watching the storio tag!

artem-zinnatullin commented 9 years ago

I'm closing this issue, feel free to comment if you have something to say :)