12

I use Retrofit with RxJava in my Android app, and my code:

public void getConfig(NetworkSubscriber subscriber) {
    Observable<Config> observable = mApi.getConfig();
    observable.subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(subscriber);
}

public void getCode(String mobile, int type, NetworkSubscriber subscriber) {
    Observable<BaseMessageEntity> observable = mApi.getCode(mobile, type);
    observable.subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(subscriber);
}

And i don't want to write .subscribeOn(Schedulers.newThread()) and .observeOn(AndroidSchedulers.mainThread()) every business method

How can i do?

Mohamed
  • 656
  • 9
  • 28
xuyanjun
  • 818
  • 7
  • 8

3 Answers3

18

If you don't want to specify the threads you want on every call, you can create a wrapper around RxJavaCallAdapterFactory to set your threads for your by default.

public class RxThreadCallAdapter extends CallAdapter.Factory {

    RxJavaCallAdapterFactory rxFactory = RxJavaCallAdapterFactory.create();
    private Scheduler subscribeScheduler;
    private Scheduler observerScheduler;

    public RxThreadCallAdapter(Scheduler subscribeScheduler, Scheduler observerScheduler) {
        this.subscribeScheduler = subscribeScheduler;
        this.observerScheduler = observerScheduler;
    }

    @Override
    public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        CallAdapter<Observable<?>> callAdapter = (CallAdapter<Observable<?>>) rxFactory.get(returnType, annotations, retrofit);
        return callAdapter != null ? new ThreadCallAdapter(callAdapter) : null;
    }

    final class ThreadCallAdapter implements CallAdapter<Observable<?>> {
        CallAdapter<Observable<?>> delegateAdapter;

        ThreadCallAdapter(CallAdapter<Observable<?>> delegateAdapter) {
            this.delegateAdapter = delegateAdapter;
        }

        @Override public Type responseType() {
            return delegateAdapter.responseType();
        }

        @Override
        public <T> Observable<?> adapt(Call<T> call) {
            return delegateAdapter.adapt(call).subscribeOn(subscribeScheduler)
              .observeOn(observerScheduler);
        }
    }
}

and then use it instead of RxJavaCallAdapterFactory.create() in your builder --

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(new RxThreadCallAdapter(Schedulers.io(), AndroidSchedulers.mainThread()))
    .build();
Radim Vaculik
  • 559
  • 4
  • 16
iagreen
  • 31,470
  • 8
  • 76
  • 90
17

To have a default scheduler for subscribeOn you can pass it as an argument straight to the RxJavaCallAdapterFactory when creating your Retrofit instance:

new Retrofit.Builder()
      .client(okHttpClient)
      .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
.build();

(For RxJava1 use RxJavaCallAdapterFactory)

Got introduced in Retrofit 2.0.0

Till - Appviewer.io
  • 4,529
  • 1
  • 31
  • 35
  • 4
    And `RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io())` for rx java 2 – Diolor Apr 24 '18 at 13:41
  • This is good answer. But then we still need to remember to add `observeOn` in our code, for example in cases where we're updating views, which should be done on main thread. – Myroslav Nov 10 '20 at 09:20
  • Maybe. If you have your Activity/Fragment [observe a LiveData](https://developer.android.com/reference/androidx/lifecycle/LiveData#observe(androidx.lifecycle.LifecycleOwner,%20androidx.lifecycle.Observer%3C?%20super%20T%3E)) of a ViewModel, as usually suggested, then `observe` ensures to be on the main thread automatically – Till - Appviewer.io Nov 10 '20 at 13:19
6

You can reduce it to one line using compose(). For example, below is a modified version of your getConfig() method. It assumes you are using retrolambda.

public void getConfig(NetworkSubscriber subscriber) {
    Observable<Config> observable = mApi.getConfig();
    observable
            .compose(this::setupThreads)
            .subscribe(subscriber);
}

The setupThreads() method would look like this:

private <T> Observable<T> setupThreads(final Observable<T> observable) {
    return observable
            .subscribeOn(Schedulers.newThread())
            .observeOn(AndroidSchedulers.mainThread());
}

A few references:

kjones
  • 5,783
  • 2
  • 27
  • 27
  • thanks, i got it. but, that's no way to solve it by rx self? – xuyanjun Nov 02 '15 at 08:01
  • @xuyanjun - `compose()` is a valuable part of RxJava so I'm not quite sure what you mean by "solve it by rx self". In this case `compose()` will allow you to re-use `setupThreads()` over and over without having to add `.subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread())` to every observable. – kjones Nov 03 '15 at 00:25