在RxJava 2(最佳实践)

时间:2017-02-14 18:37:37

标签: java android rx-java rx-android rx-java2

我目前正在构建一个小型社交媒体风格的应用程序,该应用程序利用 RxJava 2 Firebase 。我正在使用MVP样式架构,并且我使用名为AuthSource的接口抽象出了我的AuthService。

为简单起见,我将在我的服务中使用Single方法:

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.
}

最后,我将展示处理呼叫的Presenter方法:

//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();

                                }
                            }
                    )
    );
}

我意识到问题的主题有点笼统,所以我会尝试从这里缩小范围。我在上面发布的代码只要我使用Create()成功从Firebase的API获取数据。问题是,我对使用RxJava 2很新,而且我不确定这里有什么东西可以用于垃圾收集和内存泄漏。我根据RxJava 2 Docs选择使用Observable.create():

“提供一个API(通过冷Observable),将反应世界与回调式世界联系起来。”

RxJava 2 Docs 最后,我目前处理这些Observable的唯一主动是,当事件将用户带到一个新的Activity时,在我的Presenter中调用CompositeDisposable.clear()。


问题:

- 假设在Presenter完成时简单地调用CompositeDisposable.clear()是否可以安全地处理我的垃圾收集? (假设我没有在其余代码中创建内存泄漏)。

- 如果我的理解是正确的,在这种情况下,create()是比使用fromCallable()更好的选择,因为fromCallable()应该用于同步事件(即不像Firebase API回调)?

- 它就像在Observable.create()中抛出我的异步回调一样简单吗?我很害怕这是多么容易......

2 个答案:

答案 0 :(得分:5)

  

假设只是致电CompositeDisposable.clear()是否安全   当Presenter完成时,会处理我的垃圾收集吗?   (假设我还没有在其余代码中创建内存泄漏)。

比这更棘手。如果Observable引用的所有内容都属于Observable范围,则非处置Activity不会创建内存泄漏。生产者和消费者都将与Activity一起进行垃圾收集。如果您引用的资源将在Activity(例如Application级别实例化的提供程序中继续存在,则可能会发生内存泄漏。因此,如果您想使用CompositeDisposable.clear(),请确保在emitter.setCancellable()内部实施Observable.create()以处置这些漏洞资源。

  

如果我的理解是正确的,create()是更好的选择   在这种情况下,fromCallable()应该用于fromCallable()   同步事件(即不像Firebase API回调)?

create()用来命名为fromAsync()。在包装回调代码时,使用fromCallable()包装同步方法调用create()

  

是否真的像在我的异步回调中抛出一样简单   Observable.create()?我很害怕这很容易......

如果您在第一点提到的范围之外处理那些讨厌的引用,那就简单了。

通常在Android上,内存泄漏涉及Context,这很大。一定要测试你的代码。 leakcanary对此事有很大的帮助。

最后,您可以使用现有的Firebase RxJava绑定来避免自行包装。或者从他们那里获取灵感:

答案 1 :(得分:1)

  • 调用clear将从Observable中分离订阅者 - 对发出的事件作出反应的代码,结果是由演示者/活动包含并且有硬参考的订阅者将不再由观察者持有并且比演示者/活动生命周期更长寿 但是,请注意,如果您的Observable本身包含对您的演示者/活动的引用,您仍然可能导致泄漏 在任何一种情况下,当您通过静态引用您的活动/演示者或其他比您的活动/演示者更长的对象(例如应用程序)上下文时,都会发生泄漏。

  • 实际上,create()方法是从异步方法创建Observable的正确方法(BTW,在RxJava1中,有一种不同的过时方式也称为create,但它在RxJava2中被更改,因此会有没有办法错误地创建Observable,但这是一个不同的故事)

  • 嗯,你仍然需要确保你服从Observable contract, 确保会有终端事件(onComplete / onError), 在终端事件(onCompleted / onError)和背压(使用Flowable Observable强制执行)之后将没有onNext