0

I'm new to RxJava, and there are a lot of examples and answers out there, but I'm having trouble piecing together something that addresses all of my concerns.

The code below seems to be working except that I occasionally get results out of order. So I think I need to introduce a switchMap, but I'm not sure exactly where, and I wonder if I haven't already made things unnecessarily complicated, like is it odd to subscribe to the RxBinding and separately subscribe to the network call?

view.autocompleteText() is an RxBinding. I want to get text from that, call the retrofit service, and update the view with results, with all the bells and whistles like showing/hiding spinner, and error handling for the network call that won't kill the whole thing and make my textbox unresponsive.

private void handleAutocompleteText() {
    mCompositeDisposable.add(view.autocompleteText()
        .debounce(400, TimeUnit.MILLISECONDS)
        .filter(s -> s.length() >= resources.getAutocompleteThreshold())
        .observeOn(threads.main())
        .doOnNext(s -> view.setProgressVisible(true))
        .subscribe(s -> {
            mCompositeDisposable.add(mAutocompleteService.query(s.toString())
                .subscribeOn(threads.io())
                .observeOn(threads.main()).toObservable()
                .retry(3)
                .doOnNext(response -> {
                    if (response.getStatus() != 200)
                        throw new RuntimeException("Server error " + response.getStatus());
                })
                .map(response -> response.getData())
                .subscribe(items -> {
                    view.setProgressVisible(false);
                    view.updateList(items);
                }, error -> {
                    view.setProgressVisible(false);
                    view.showMessage(resources.getListError());
                }));
            }, error -> {
                view.setProgressVisible(false);
                view.showMessage(resources.getListError());
            }
        )
    );
}

Is there a better way to do this, and where can I introduce a switchMap to discard any inflight searches and only update the view with results of the last one? And if the answer is drastically different, I'd really appreciate a walkthrough.

Thanks in advance!!

John
  • 27
  • 1
  • 9

1 Answers1

2

I am not sure this is you want. But it might give you hints and solutions. Let's see the code. The switchMap gets parameter from view and changes observable to resrofit observable. And then it returns response from API call. After all of that you can receive the response and use the response.

If the code doesn't work let me know.

mCompositeDisposable.add(
        view
                .autocompleteText()
                .debounce(400, TimeUnit.MILLISECONDS)
                .filter({ s -> s.length() >= resources.getAutocompleteThreshold() })
                .observeOn(threads.main())
                .doOnNext({ s -> view.setProgressVisible(true) })
                .map({ s -> s.toString())}
                .switchMap({ text -> mAutocompleteService.query(text))}
                .subscribeOn(threads.io())
                .observeOn(threads.main())
                .retry(3)
                .doOnNext({ response ->
                    if (response.getStatus() !== 200)
                        throw RuntimeException("Server error " + response.getStatus())
                })
                .map({ response -> response.getData() })
                .subscribe({ items ->
                    view.setProgressVisible(false)
                    view.updateList(items)
                }, { error ->
                    view.setProgressVisible(false)
                    view.showMessage(resources.getListError())
                })
)
Kh Jung
  • 313
  • 1
  • 9
  • Thanks! I tried out something similar, and it does seem to work, but once successful results are returned the whole chain goes dead, so the user can't delete text and start over with a different search. I guess that makes sense that the observer is done when you reach success and why I ended up with 2 subscribes. I need the textbox observer to continue working as long as the page is active. Maybe I can't use switchMap and have to use the switch strategy I learned from this crazy video: https://youtu.be/rUZ9CjcaCEw. I guess they're not quite the same thing. – John Feb 15 '19 at 14:07
  • `the whole chain goes dead` <-- What is mean? The `disposable` was `disposed`? Interesting Did you see any messages in `subscribe` or `logcat`? – Kh Jung Feb 16 '19 at 01:25
  • I'm sorry! This is working with the switchMap! I had added in a distinctUntilChanged(), and that is what had stopped it from emitting. Not sure why that's not working as I expect, but that's a different issue. Thanks!! – John Feb 18 '19 at 17:38