4

I just started exploring RxJava recently and applied it to a small part of my project. It turns out this part is small but one with 'high traffic': it gets called a lot by other components. An example would be a network client that gets called repeatedly to fetch remote data, applies a few transformations to the response, then fires callback event. Let's just say these transformations are lightweight so I can do it on main thread:

restService.getData() // retrofit interface that returns Observable<T>
    .observeOn(AndroidSchedulers.mainThread())
    .map(data -> someMapping(data))
    .map(data -> someOtherMapping(data))
    .subscribe(this::fireResponseCallback, this::fireErrorCallback)

Now the same could be done without RxJava:

restService.getData() // retrofit interface that returns Call<T>
    .enqueue(new Callback<T>() {
        @Override
        public void onResponse(Call<T> call, Response<T> response) {
            T data = response.body();
            data = someMapping(data);
            data = someOtherMapping(data);
            fireResponseCallback(data);
        }

        @Override
        public void onFailure(Call<T> call, Throwable t) {
            fireErrorCallback(t);
        }
    });

What I observe with RxJava is that it creates a lot of more objects in memory. For the example above, each execution go through 4 lambda expressions, each makes 1 instantiation of anonymous class (Func1<> or Action1<>). Without RxJava, you only have 1 instantiation of anonymous class (Callback<T>). This difference widens quickly as the same logic gets triggered multiple times. I wonder if this is something that I should be mindful about when using RxJava? If yes then what would be good practices to keep the number of objects small?

1 Answer 1

3

Yes, RxJava 1.x allocates more objects than theoretically needed for a reactive sequence (due to some design choices) but it shouldn't be that drastic. It's allocation rate becomes apparent for synchronous local sequences but rarely for network-based sequences.

If your Action and Func lambdas are pure, you can pre-allocate them in member fields and just reuse their references in the lambdas. In addition, if restService.getData() is consumable multiple times, you can save the entire chain into a field and just call subscribe whenever needed.

class DataAccess {
    final RestService restService;

    final Observable<T> call = restService.getData()
        .observeOn(AndroidSchedulers.mainThread())
        .map(data -> someMapping(data))
        .map(data -> someOtherMapping(data));

    final Action1<T> consumer = this::fireResponseCallback;

    final Action1<Throwable> errorHandler = this::fireErrorCallback;

    DataAccess(RestService restService) {
        this.restService = restService;
    }

    void doDataAccess() {
        call.subscribe(consumer, errorHandler);
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.