8

I'm currently building a small Social Media style App which leverages RxJava 2 and Firebase. I'm using MVP style architecture, and I've abstracted out my AuthService with an interface called AuthSource.

For simplicity's sake, I'll work with a Single method in my Service:

public class FirebaseAuthService implements AuthSource {

private FirebaseAuth auth;
private FirebaseAuth.AuthStateListener listener;

//initialization code

@Override
public Maybe<User> getUser() {
    return Maybe.create(new MaybeOnSubscribe<User>() {
                            @Override
                            public void subscribe(final MaybeEmitter<User> e) throws Exception {
                                if (auth == null) {
                                    auth = FirebaseAuth.getInstance();
                                }

                                if (listener != null) {
                                    auth.removeAuthStateListener(listener);
                                }

                                listener = new FirebaseAuth.AuthStateListener() {
                                    @Override
                                    public void onAuthStateChanged(@NonNull FirebaseAuth firebaseAuth) {
                                        FirebaseUser firebaseUser = firebaseAuth.getCurrentUser();
                                        auth.removeAuthStateListener(listener);
                                        if (firebaseUser != null) {
                                            User user = new User(
                                                    firebaseUser.getDisplayName(),
                                                    firebaseUser.getEmail());

                                            user.setUserId(firebaseUser.getUid());


                                            Uri photoUrl = firebaseUser.getPhotoUrl();
                                            if (photoUrl != null){
                                                user.setProfilePhotoUrl(photoUrl.toString());
                                            }
                                            e.onSuccess(user);
                                        } else {
                                            e.onComplete();
                                        }
                                    }
                                };

                                auth.addAuthStateListener(listener);
                            }
                        }
    );

}

}

interface AuthSource {
    Maybe<User> getUser();
//Other methods etc.
}

Finally, I'll show my Presenter method which handles the call:

//from with a Presenter:
@Override
private void getUserData() {
    disposableSubscriptions.add(
            auth.getUser().subscribeOn(schedulerProvider.io())
                    .observeOn(schedulerProvider.ui())
                    .subscribeWith(
                            new DisposableMaybeObserver<User>() {

                                @Override
                                public void onError(Throwable e) {
                                    view.makeToast(R.string.error_retrieving_data);
                                    view.startDispatchActivity();
                                }

                                @Override
                                public void onComplete() {

                                }

                                @Override
                                public void onSuccess(User user) {
                                    ProfilePagePresenter.this.currentUser = user;
                                    view.setName(user.getName());
                                    view.setEmail(user.getEmail());
                                    if (user.getProfilePhotoUrl().equals("")) {
                                        view.setDefaultProfilePhoto();
                                    } else {
                                        view.setProfilePhotoURI(user.getProfilePhotoUrl());
                                    }

                                    getUserProfileFromDatabase();

                                }
                            }
                    )
    );
}

I realize the topic of the question is a bit general, so I'll try to narrow things down from here. The code I've posted above works insofar as I'm succesfully getting Data from Firebase's API using Create(). The problem is, I'm quite new to using RxJava 2, and I'm not certain what's going on under the hood here for garbage collection and memory leaks. I chose to use Observable.create() as per the RxJava 2 Docs:

"Provides an API (via a cold Observable) that bridges the reactive world with the callback-style world."

RxJava 2 Docs Finally, the only proactive thing I'm doing at the moment to dispose of these Observables, is to call CompositeDisposable.clear() in my Presenter when events take the user to a new Activity.


Questions:

-Is it safe to assume that simply calling CompositeDisposable.clear() when the Presenter finishes, will handle my Garbage collection? (assuming I haven't created memory leaks in the rest of the code).

-If my understanding is correct, create() is a better option to use than fromCallable() in this case, as fromCallable() should be used for Synchronous events (i.e. not something like Firebase API callbacks)?

-Is it really as simple as just throwing my Asynchronous callbacks in Observable.create()? I'm terrified at how easy that is to do...

2 Answers 2

6

Is it safe to assume that simply calling CompositeDisposable.clear() when the Presenter finishes, will handle my Garbage collection? (assuming I haven't created memory leaks in the rest of the code).

It's a little trickier than this. Non-disposed Observable won't create memory leak if everything referenced by the Observable belong to the Activity scope. Both the producer and the consumer will be garbage collected alongside Activity. Memory leak may occur if you referenced resources that will survive the Activity, a provider instantiated at Application level for example. So if you want to use CompositeDisposable.clear() make sure to implement emitter.setCancellable() inside Observable.create() to dispose those leaky resources.

If my understanding is correct, create() is a better option to use than fromCallable() in this case, as fromCallable() should be used for Synchronous events (i.e. not something like Firebase API callbacks)?

create() use to be named fromAsync(). Use fromCallable() to wrap a synchronous method call, create() when wrapping callback code.

Is it really as simple as just throwing my Asynchronous callbacks in Observable.create()? I'm terrified at how easy that is to do...

It is as easy ... if you take care of those pesky references outside of scope as mentioned at the first point.

Usually on Android, a memory leak involve the Context, which is big. Be sure to test your code. leakcanary is a great help for this matter.

Last, you could avoid doing the wrapping yourself by using an existing Firebase RxJava binding. Or take inspiration from them:

Sign up to request clarification or add additional context in comments.

Comments

2
  • Calling clear will detach the subscriber - the code that reacts to the emitted events, from the Observable, and as a result the subscriber which is enclosed by the presenter/activity and has hard reference to it, will no longer be held by the observer and lived longer than the presenter/activity lifecycle.
    But, beware, you still can cause leaks if your Observable itself contains references to your presenter/activity.
    In either cases, leak will occur when you reference your activity/presenter by static or other object that lives in longer (for instance Application) context than your activity/presenter.

  • Indeed, create() method is the correct way to create Observable from async method (BTW, in RxJava1, there was a different obsolete way that called also create, but it was changed in RxJava2, so there will be no way of creating Observable wrongly, but that's a different story)

  • Well, you still need to make sure you obey to the Observable contract, make sure that there will be terminal event (either onComplete/onError), there will be no onNext after terminal event (onCompleted/onError), and backpressure (which is enforced with Flowable Observable)

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.