MvpAndroidAndroid组件化

RXJava2+Retrofit2+MVP+RXLifecycl

2018-04-04  本文已影响731人  Obsession丶执

本文所涉及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

上一篇下一篇

猜你喜欢

热点阅读