【问题标题】:What is the proper way to handle subscriptions in RxJava/RxAndroid for an Activity Lifecycle?在 RxJava/RxAndroid 中为 Activity 生命周期处理订阅的正确方法是什么?
【发布时间】:2015-10-26 01:03:57
【问题描述】:

我刚刚开始使用 RxJava/RxAndroid。我想避免上下文泄漏,所以我像这样创建了一个 BaseFragment:

public abstract class BaseFragment extends Fragment {

    protected CompositeSubscription compositeSubscription = new CompositeSubscription();

    @Override
    public void onDestroy() {
        super.onDestroy();

        compositeSubscription.unsubscribe();
    } 
} 

在我扩展 BaseFragment 的片段中,我正在这样做:

protected void fetchNewerObjects(){
        if(!areNewerObjectsFetching()){ //if it is not already fetching newer objects

            Runtime.getRuntime().gc();//clean out memory if possible

            fetchNewObjectsSubscription = Observable
                .just(new Object1())
                .map(new Func1<Object1, Object2>() {
                    @Override
                    public Object2 call(Object1 obj1) {
                        //do bg stuff
                        return obj2;
                    }
                })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Object2>() {
                    @Override
                    public void onCompleted() {
                        compositeSubscription.remove(fetchNewObjectsSubscription);
                        fetchNewObjectsSubscription = null;
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onNext(ArrayList<NewsFeedObject> newsFeedObjects) {
                        //do stuff
                    }
                });

        //add subscription to composite subscription so it can be unsubscribed onDestroy()
        compositeSubscription.add(fetchNewObjectsSubscription);
    }
}

protected boolean areNewerObjectsFetching(){
    if(fetchNewObjectsSubscription == null || fetchNewObjectsSubscription.isUnsubscribed()){ //if its either null or is in a finished status
        return false;
    }
    return true;
}

所以我想我的问题有两个方面:

  1. 是否会因为我取消订阅 onDestroy() 而停止上下文泄漏?

  2. 我是否通过在完成后将订阅设置为 null 并检查 nullity 来正确跟踪 observable 是否“正在运行”?

【问题讨论】:

    标签: java android rx-java rx-android


    【解决方案1】:

    您不需要任何第三方库来管理 Activity 生命周期。试试下面的代码:

    public class LifecycleBinder {
    
        public static <R> Observable.Transformer<R, R> subscribeUtilEvent(final Activity target, LifecycleEvent event) {
            final Application app = target.getApplication();
            final PublishSubject<LifecycleEvent> publishSubject = PublishSubject.create();
            final Application.ActivityLifecycleCallbacks callbacks = new Application.ActivityLifecycleCallbacks() {
                @Override
                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    
                }
    
                @Override
                public void onActivityStarted(Activity activity) {
    
                }
    
                @Override
                public void onActivityResumed(Activity activity) {
    
                }
    
                @Override
                public void onActivityPaused(Activity activity) {
                    if (activity == target)
                        publishSubject.onNext(LifecycleEvent.ON_PAUSED);
                }
    
                @Override
                public void onActivityStopped(Activity activity) {
                    if (activity == target)
                        publishSubject.onNext(LifecycleEvent.ON_STOPPED);
                }
    
                @Override
                public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
                    if (activity == target)
                        publishSubject.onNext(LifecycleEvent.ON_SAVE_INSTANCE_STATE);
                }
    
                @Override
                public void onActivityDestroyed(Activity activity) {
                    if (activity == target)
                        publishSubject.onNext(LifecycleEvent.ON_DESTROYED);
                }
            };
    
            app.registerActivityLifecycleCallbacks(callbacks);
            return subscribeUtilEvent(publishSubject, event, new Action0() {
                @Override
                public void call() {
                    app.unregisterActivityLifecycleCallbacks(callbacks);
                }
            });
        }
    
        public static <R> Observable.Transformer<R, R> subscribeUtilEvent(final Fragment target, LifecycleEvent event) {
            final FragmentManager manager = target.getFragmentManager();
            if (manager == null) {
                throw new NullPointerException("fragment manager is null!");
            }
    
            final PublishSubject<LifecycleEvent> publishSubject = PublishSubject.create();
            final FragmentManager.FragmentLifecycleCallbacks callbacks = manager.new FragmentLifecycleCallbacks() {
    
                @Override
                public void onFragmentPreAttached(FragmentManager fm, Fragment f, Context context) {
                }
    
                @Override
                public void onFragmentAttached(FragmentManager fm, Fragment f, Context context) {
                }
    
                @Override
                public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
                }
    
                @Override
                public void onFragmentActivityCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {
                }
    
                @Override
                public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v, Bundle savedInstanceState) {
                }
    
                @Override
                public void onFragmentStarted(FragmentManager fm, Fragment f) {
                }
    
                @Override
                public void onFragmentResumed(FragmentManager fm, Fragment f) {
                }
    
                @Override
                public void onFragmentPaused(FragmentManager fm, Fragment f) {
                    if (f == target)
                        publishSubject.onNext(LifecycleEvent.ON_PAUSED);
                }
    
                @Override
                public void onFragmentStopped(FragmentManager fm, Fragment f) {
                    if (f == target)
                        publishSubject.onNext(LifecycleEvent.ON_STOPPED);
                }
    
                @Override
                public void onFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) {
                    if (f == target)
                        publishSubject.onNext(LifecycleEvent.ON_SAVE_INSTANCE_STATE);
                }
    
                @Override
                public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {
                    if (f == target)
                        publishSubject.onNext(LifecycleEvent.ON_VIEW_DESTORYED);
                }
    
                @Override
                public void onFragmentDestroyed(FragmentManager fm, Fragment f) {
                    if (f == target)
                        publishSubject.onNext(LifecycleEvent.ON_DESTROYED);
                }
    
                @Override
                public void onFragmentDetached(FragmentManager fm, Fragment f) {
                    if (f == target)
                        publishSubject.onNext(LifecycleEvent.ON_DESTROYED);
                }
            };
            manager.registerFragmentLifecycleCallbacks(callbacks, true);
    
            return subscribeUtilEvent(publishSubject, event, new Action0() {
                @Override
                public void call() {
                    manager.unregisterFragmentLifecycleCallbacks(callbacks);
                }
            });
        }
    
        private static <R, T> Observable.Transformer<R, R> subscribeUtilEvent(final Observable<T> source, final T event, final Action0 doOnComplete) {
            return new Observable.Transformer<R, R>() {
                @Override
                public Observable<R> call(Observable<R> rObservable) {
                    return rObservable.takeUntil(takeUntilEvent(source, event)).doOnCompleted(doOnComplete);
                }
            };
        }
    
        private static <T> Observable<T> takeUntilEvent(final Observable<T> src, final T event) {
            return src.takeFirst(new Func1<T, Boolean>() {
                @Override
                public Boolean call(T lifecycleEvent) {
                    return lifecycleEvent.equals(event);
                }
            });
        }
    }
    

    生命周期事件:

    public enum LifecycleEvent {
        ON_PAUSED,
        ON_STOPPED,
        ON_SAVE_INSTANCE_STATE,
        ON_DESTROYED,
        ON_VIEW_DESTORYED,
        ON_DETACHED,
    }
    

    用法:

    myObservable
       .compose(LifecycleBinder.subscribeUtilEvent(this, LifecycleEvent.ON_DESTROYED))
       .subscribe();
    

    【讨论】:

      【解决方案2】:
      1. 是的,它会停止,但您还应该在onError 中也将订阅设置为null(或出错后,您将不会再次加载项目)。

        也不要忘记片段可以被停止,但不能被销毁 (例如,在后台堆栈中)并且您可能不想观察 在这种情况下任何事情。 如果您将 unsubscribeonDestroy 移动到 onStop,请不要忘记在每次创建视图时在 onCreateView 中初始化 compositeSubscription(因为在取消订阅 CompositeSubscription 后,您不再可以在那里添加订阅)。

      2. 是的,正确。但我认为compositeSubscription.remove 可以省略,因为你已经检查了null。

      【讨论】:

      • 所以如果我在 onStop 中取消订阅,并且它永远不会更新我的视图,那么我需要在 onResume 中重新运行 fetchNewObjects() 吗?
      • 另外,为什么要 onCreate?你是说 onCreateView 吗?
      • 我更喜欢在onCreate中做,因为它在onCreateView之前被调用,所以compositeSubscription在使用前就准备好了
      • 但根据文档,它永远不会命中 onCreate()。它从 onDestroyView() 到 onCreateView() developer.android.com/intl/zh-cn/guide/components/…
      • 抱歉,对,在 onCreateView 中,我更新了答案。关于 onStop - 取消订阅“停止”处理 observable,所以,是的,如果尚未加载数据,您可能希望再次加载数据。
      猜你喜欢
      • 1970-01-01
      • 2022-12-14
      • 2020-05-31
      • 1970-01-01
      • 2019-02-02
      • 1970-01-01
      • 2018-07-10
      • 1970-01-01
      相关资源
      最近更新 更多