Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxJava's .debounce() interfering with my Observable's threads and error handling

I want to make a standard search in my Android app, where I type in an EditText, wait a bit until the user is done typing, and fire up a network request using Retrofit :

// make observable out of EditText
Observable<OnTextChangeEvent> textObs = WidgetObservable.text(searchText);

mSearchResultSubscription =
    textObs

        // wait until user has not typed for 350 milliseconds
        .debounce(350, TimeUnit.MILLISECONDS)

        // get the string the user typed
        .map(OnTextChangeEvent::text)
        .map(CharSequence::toString)

        // start a new observable (from Retrofit)
        .flatMap(
            q ->
                // try network call and return my data
                MyRetrofitAPI.getService().search(q)

                    // if this fails, just return empty observable
                    .onErrorResumeNext(error -> {
                        Log.e("Error from retrofit: " + error.getLocalizedMessage());
                        return Observable.empty();
                    })

        )

        // if all is well, show the contents on the screen somehow
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(a -> {
                mAdapter.setItems(a);
            }
            , error -> {
                Log.e("Also error in outer observable: " + error.getLocalizedMessage());
            }
        );

Now, I have a testserver that takes the retrofit call and returns a list. When I type 'crash' the server executes some invalid code and errors, returning http status code 500, and some error html. So, the retrofit call fails.

I would think the outer Observable chain should not be effected by this. See my previous question: In RxJava, how to retry/resume on error, instead of completing the observable

But, the outer Observable also errors, causing the chain to terminate. The error is: The current thread must have a looper!

Strange. Now I try without the .debounce() and the same thing happens, server has an internal error, but the outer Observable does not error.

So what is it about .debounce() that it does to threads that is causing this behaviour? And how can I work around it?

like image 799
xorgate Avatar asked Jul 15 '15 15:07

xorgate


2 Answers

Adding to pturner's answer, the Scheduler can be passed as

.debounce(400, TimeUnit.MILLISECONDS, AndroidSchedulers.mainThread())

This will cause the observer to work on the Main thread (UI thread) of Android, and will prevent Observer from throwing error.

like image 98
kushpf Avatar answered Oct 27 '22 01:10

kushpf


Seems like the issue may be with debounce creating a new thread for the code to execute, from the docs:

This variant operates by default on the computation Scheduler, but you can optionally pass in a Scheduler of your choosing as a third parameter.

You might need to pass in an Android scheduler with a background Looper which would solve the error (in theory, unfortunately can't run your stuff right now without the server).

like image 42
pturner Avatar answered Oct 27 '22 01:10

pturner