美文网首页MvpAndroidAndroid组件化
RXJava2+Retrofit2+MVP+RXLifecycl

RXJava2+Retrofit2+MVP+RXLifecycl

作者: Obsession丶执 | 来源:发表于2018-04-04 17:39 被阅读731次

    本文所涉及DEMO已上传至https://github.com/LegendaryMystic/HYMVP
    本人小白一个,文章废话较多,如果你觉得talk is cheap,喜欢直接 read the fuck source code,可跳过直接前往
    码字不易,如果代码能够帮到你,望不吝给个鼓励的star,感谢!

    RxJava问世至今其火爆程度已可见一斑,加之眼下普遍流行使用的基于OKHttp的Retrofit网络请求框架对其完美支持,使得其如王者农药一般饱受一众屌丝Android程序猿的喜爱。农药玩的人多了,你就不得不掌握一些骚套路,才能上你们最爱的“王者”。

    本文正是本着学习的态度,也谈一谈RxJava+Retrofit结合MVP架构模式在实际项目中你可能需要的一些基本的骚操作。

    在此之前,如果你还不了解RxJava请传送至扔物线的给 Android 开发者的 RxJava 详解;如果你还没使用过Retrofit,那....请自便,看Retrofit官网吧,或者你需要我教你请点这里.

    也谈MVP

    对于MVP,全称Model-View-Presenter,众所周知它是从经典的MVC模式演变而来的。

    mvp.jpg

    在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会直接从Model中读取数据而不是通过 Controller。

    在MVC里,View是可以直接访问Model的!从而,View里会包含Model信息,不可避免的还要包括一些业务逻辑。 在MVC模型里,更关注的Model的不变,而同时有多个对Model的不同显示,即View。所以,在MVC模型里,Model不依赖于View,但是View是依赖于Model的。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。

    虽然 MVC 中的 View 的确“可以”访问 Model,但是我们不建议在 View 中依赖 Model,而是要求尽可能把所有业务逻辑都放在 Controller 中处理,而 View 只和 Controller 交互。

    总结一下,在MVP里,Presenter完全把Model和View进行了分离,主要的程序逻辑在Presenter里实现。模型与视图完全分离,我们可以修改视图而不影响模型,而且,Presenter与具体的View是没有直接关联的,而是通过定义好的接口进行交互,从而使得在变更View时候可以保持Presenter的不变,即重用! 不仅如此,我们还可以编写测试用的View,模拟用户的各种操作,从而实现对Presenter的测试(单元测试)

    套路一:订阅和取消订阅问题

    RxJava基于观察者模式,一般当我们借助RxJava请求网络数据时,需要网络返回数据后更新UI,此时如果视图已经消亡,则需要在对应的生命周期取消订阅,否则会导致内存泄漏。
    简单的,我们在视图消亡后,无需RxJava再执行,可以直接取消订阅

     if (!subscription.isUnsubscribed()) {
            subscription.unsubscribe();
        }
     observable.unsubscribeOn(Schedulers.io());
    

    可用在activity的 onDestroy(), Fragment的 onDestroyView()中调用。
    那在MVP模式中,只要我们在Presenter在基类中定义一个CompositeDisposable容器,将请求订阅disaposable添加到容器里统一管理,必要时clear即可。

    protected CompositeDisposable mCompositeDisposable;
    
        /**
         * 将 {@link Disposable} 添加到 {@link CompositeDisposable} 中统一管理
         * 可在 {@link Activity#onDestroy()} 中使用 {@link #unDispose()} 停止正在执行的 RxJava 任务,避免内存泄漏
         * 目前已使用 {@link RxLifecycle} 避免内存泄漏,此方法作为备用方案
         *
         * @param disposable
         */
        protected void addDisposabel(Disposable disposable) {
            if (mCompositeDisposable == null) {
                mCompositeDisposable = new CompositeDisposable();
            }
            //将所有 Disposable 放入集中处理
            mCompositeDisposable.add(disposable);
        }
    
        public void unDispose(){
    
            if (mCompositeDisposable != null) {
                mCompositeDisposable.clear();//保证 Activity 结束时取消所有正在执行的订阅
            }
        }
    

    这里我们采用另一种方案:

    套路二: RxLifecycle + MVP

    如果你有心不难发现Github上已有人对RxJava 管理订阅的问题作出了贡献:RxLifecycle

    Github: https://github.com/trello/RxLifecycle

    常规的,RxLifecycle使用很简单,只需要集成rxlifecycle-components组件,Components包中包含RxActivity、RxFragment等等,可以用Rxlifecycle提供的,也可以自定义。

    让你的BaseActivity继承RxAppCompatActivity,然后像这样给你的Observable绑定lifecycle

    myObservable
        .compose(RxLifecycle.bind(lifecycle))
        .subscribe();
    

    或者你也可以指定bind特定生命周期事件:

    myObservable
        .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY))
        .subscribe();
    

    然而这都不是重点,重点是如何在MVP模式里使用呢?我的答案很简单:
    在View的接口基类里增加一个接口:

    public interface BaseView {
    
        <T> LifecycleTransformer<T> bindToLifecycle();
    
        /**
         * 显示加载
         */
        void showLoading();
    
        /**
         * 隐藏加载
         */
        void hideLoading();
    }
    

    而你的Activity基类BaseActivity继承自RxAppCompatActivity自然也就实现了<T> LifecycleTransformer<T> bindToLifecycle();这个接口方法,这样我们只需要在Presenter里使用的时候像上面一样给Observable bindToLifecycle即可。这个的封装代码将在下一个套路讲解一并展示,看完你会恍然大悟。

    接下来,如你所见,我们的BaseActivity基类直接继承RxLifecycle的RxAppCompatActivity,那么问题来了,也许你以后还需要使用一些其他的第三方,而它又需要你继承它的Activity,然而Java是没有多继承的,显然这样还不够完善。

    此时,如果你稍有Read the fucking Source code,这里附上RxAppCompatActivity的源码

    public abstract class RxAppCompatActivity extends AppCompatActivity implements LifecycleProvider<ActivityEvent> {
    
        private final BehaviorSubject<ActivityEvent> lifecycleSubject = BehaviorSubject.create();
    
        @Override
        @NonNull
        @CheckResult
        public final Observable<ActivityEvent> lifecycle() {
            return lifecycleSubject.hide();
        }
    
        @Override
        @NonNull
        @CheckResult
        public final <T> LifecycleTransformer<T> bindUntilEvent(@NonNull ActivityEvent event) {
            return RxLifecycle.bindUntilEvent(lifecycleSubject, event);
        }
    
        @Override
        @NonNull
        @CheckResult
        public final <T> LifecycleTransformer<T> bindToLifecycle() {
            return RxLifecycleAndroid.bindActivity(lifecycleSubject);
        }
    
        @Override
        @CallSuper
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            lifecycleSubject.onNext(ActivityEvent.CREATE);
        }
    
        @Override
        @CallSuper
        protected void onStart() {
            super.onStart();
            lifecycleSubject.onNext(ActivityEvent.START);
        }
    
        @Override
        @CallSuper
        protected void onResume() {
            super.onResume();
            lifecycleSubject.onNext(ActivityEvent.RESUME);
        }
    
        @Override
        @CallSuper
        protected void onPause() {
            lifecycleSubject.onNext(ActivityEvent.PAUSE);
            super.onPause();
        }
    
        @Override
        @CallSuper
        protected void onStop() {
            lifecycleSubject.onNext(ActivityEvent.STOP);
            super.onStop();
        }
    
        @Override
        @CallSuper
        protected void onDestroy() {
            lifecycleSubject.onNext(ActivityEvent.DESTROY);
            super.onDestroy();
        }
    }
    
    

    不难看出,它里面就是创建了一个BehaviorSubject 对象,BehaviorSubject是Subject的子类,首先我们来回顾一下这个Subject对象:

    如何理解Subject呢?

    在RxJava里面,Observable是数据的发射者,它会对外发射数据,然后经过map、flatmap等等数据处理后,最终传递给Observer,这个数据接收者。因此,抛开中间数据处理不管,可以看出,Observable对外发射数据,是数据流的开端;Observer接收数据,是数据流的末端。

    那么Subject呢?看一眼源码:

    /**
     * Represents an {@link Observer} and an {@link Observable} at the same time, allowing
     * multicasting events from a single source to multiple child {@code Observer}s.
     * <p>
     * All methods except the {@link #onSubscribe(io.reactivex.disposables.Disposable)}, {@link #onNext(Object)},
     * {@link #onError(Throwable)} and {@link #onComplete()} are thread-safe.
     * Use {@link #toSerialized()} to make these methods thread-safe as well.
     *
     * @param <T> the item value type
     */
    public abstract class Subject<T> extends Observable<T> implements Observer<T> {}
    

    首先,它extends Observable,说明Subject具备了对外发射数据的能力,即拥有了from()、just()等等;另外,它又implements Observer,说明又能够处理数据,具备onNext()、onCompleted等等。

    然后通过这个subject对象监听Activity生命周期事件然后再发射出去。我们的observable调用bindToLifecycle时就实现了通过subject监听并转发射Activity的生命周期事件,比如我我们绑定了Activity的destroy事件,当我们的observable收到了这个destroy事件就过滤掉不再传下去,做后面的UI绘制操作。

    那其实,说了这么多,最简单粗暴的解决方法就是必要时将上述代码copy到你的BaseActivity里即可_

    套路三: Scheduler + ObservableTransformer 线程调度

    RxJava其中一个牛逼之处就在于其提供了便利自由的线程控制,然而在使用RxJava配合进行网络请求时,你是否会发现你经常需要频繁得敲如下代码:

    observable.subscribeOn(Schedulers.io())
              .observeOn(AndroidSchedulers.mainThread())
    

    我这里用了一个工具方法便将上述绑定 Rxlifecycle 一并封装了:

       /**
         * 界面请求,不需要加载和隐藏loading时调用 使用RxLifeCycle
         * 传入view接口,Activity,Fragment等实现了view接口,Activity,Fragment继承于{@link com.trello.rxlifecycle2.components.support.RxAppCompatActivity}
         * 也就实现了bindToLifecycle方法
         * @param view View
         * @param <T> 泛型
         * @return
         */
        public static <T> ObservableTransformer<T, T> transform(final BaseView view) {
            return observable -> observable.subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .compose(view.bindToLifecycle());
        }
    
    

    使用时只需利用compose操作符调用即可。废话有点多了,详情请见源代码HYMVP由于篇幅问题,后续诸多套路,请听下回分解。

    附上源代码地址:https://github.com/LegendaryMystic/HYMVP

    相关文章

      网友评论

      • Todo2:组件化和插件化的开发里程总结
        https://www.jianshu.com/p/df2a6717009d
      • 04a8107d0143:<T> LifecycleTransformer<T> bindToLifecycle(); 这个方法,子类Activity还是需要实现的吧,要不然会编译都不过啊?
        Obsession丶执:@fread 你的IView接口方法里面要提供<T> LifecycleTransformer<T> bindToLifecycle(),子Activity要继承RxAppCompatActivity
        04a8107d0143:@Obsession丶执 我的子Activity实现了IView的话,需要去实现bindlifecycle(); 不实现的话会一直提示 有未实现的方法
        Obsession丶执:不会啊,编译没问题啊,父类RxAppCompatActivity里实现了同名方法。我们现在赶项目,有点忙。。。

      本文标题:RXJava2+Retrofit2+MVP+RXLifecycl

      本文链接:https://www.haomeiwen.com/subject/igclhftx.html