RxJava2开发小记:用CompositeDisposable来“安排”Retrofit网络请求

8102年,应该有很多新项目用的是RxJava2+Retrofit2来开发了,刚开始接触的时候确实需要一些精力去学习(记得之前看到一些大佬写的关于RxJava的介绍,说到其雄心勃勃远不止一个框架这么简单),和传统的开发模式还是有点差异的。不过慢慢地,你就会爱上介种套路。

万丈高楼平地起,先对Retrofit进行一些简单封装,方便外部调用(熟悉的同学可以忽略):

public class RetrofitFactory {
    private static OkHttpClient sOkHttpClient;
    private static Retrofit sRetrofit;
    // 创建网络请求Observable
    public static RetrofitInterface createRequest() {
        return getRetrofit().create(RetrofitInterface.class);
    }
    // 配置Retrofit,这里的单例仅作简单示意
    private synchronized static Retrofit getRetrofit() {
        if (sRetrofit == null) {
            sRetrofit = new Retrofit.Builder()
                    .baseUrl("http://test.com") // 对应服务端的host
                    .client(getHttpClient())
                    .addConverterFactory(GsonConverterFactory.create()) // 这里还结合了Gson
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) // 把Retrofit请求转化成RxJava的Observable
                    .build();
        }
        return sRetrofit;
    }
    // OkHttpClient的配置初始化就省略了,这个不是重点
    private synchronized static OkHttpClient getHttpClient() { ... };
    ...
}

getRemoteData是RetrofitInterface接口之一,示例如下:

public interface RetrofitInterface {
    // 获取远程服务器的数据
    @GET("test/getData")
    Observable<DataClass> getRemoteData();
}

基础设施搞定后,我们要发起网络请求,一般会这样写:

// 创建网络请求的Observable
Observable<DataClass> remoteDataObservable = RetrofitFactory.createRequest()
        .getRemoteData()
        .subscribeOn(Schedulers.io()) // 订阅触发后,在子线程中进行请求
        .map(dataResponse -> {
            DataClass remoteData = dataResponse;
            // 假装对返回数据做了一些处理
            // ...
            return remoteData;
        })
        .observeOn(AndroidSchedulers.mainThread()); // 在UI线程中暗中观察并及时消费
        
// 然后在需要的地方订阅刚才创建的可观察对象,返回一个Disposable对象,后面我们会用到
Disposable disposable = remoteDataObservable.subscribe(remoteData -> {
    // 在回调中,UI线程食用远程数据
    // ...
});

需要注意的是,只有在调用Observable的subscribe方法时,网络请求才会触发,订阅即触发。
就这样,整个网络请求的过程就完毕了,完结撒花……个铲铲。

正文开始了:
如果在请求过程中,UI层destroy了怎么办,不及时取消订阅,可能会造成内存泄漏。因此,CompositeDisposable就上场了,它可以对我们订阅的请求进行统一管理。
大致三步走:
1、在UI层创建的时候(比如onCreate之类的),实例化CompositeDisposable;
2、把subscribe订阅返回的Disposable对象加入管理器;
3、UI销毁时清空订阅的对象。

private CompositeDisposable mCompositeDisposable;
// when create UI
mCompositeDisposable = new CompositeDisposable();
// when request data
if (mCompositeDisposable != null && !mCompositeDisposable.isDisposed()) {
    mCompositeDisposable.add(disposable);
}
// when destroy UI
if (mCompositeDisposable != null) {
    mCompositeDisposable.clear(); // clear时网络请求会随即cancel
    mCompositeDisposable = null;
}

这样我们就可以管理脱缰的网络请求了,相当于将它与UI的生命周期绑定。只要稍稍将上述模板封装一哈,就比较方便了。比如add操作可以封装一个方法,每次网络请求时add一发就好。
对于MVP架构的项目,CompositeDisposable完全可以封装到Presenter当中。这里就不展开了。

多说两句:
那么,Disposable是什么东西呢?我们查看Observable源码,发现上述的subscribe方法实际上返回了一个Disposable对象:

@CheckReturnValue
@SchedulerSupport(SchedulerSupport.NONE)
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError) {
    return subscribe(onNext, onError, Functions.EMPTY_ACTION, Functions.emptyConsumer());
}

第一次见到这个单词,我也是很疑惑的,查下字典发现,disposable有一次性使用,可任意处置的意思(形容词、名词都有),其词根应该是动词dispose,有安排,处置的意思。
看来RxJava的作者大佬们表达得非常到位,你看我们的网络请求不就是天天被安排的对象么?
再一看Disposable的源码,其实就是一个非常简单的接口类,窥探其方法,含义就更加清晰了:

package io.reactivex.disposables;

/**
 * Represents a disposable resource.
 */
public interface Disposable {
    /**
     * Dispose the resource, the operation should be idempotent.
     */
    void dispose(); // 安排!

    /**
     * Returns true if this resource has been disposed.
     * @return true if this resource has been disposed
     */
    boolean isDisposed(); // 安排完了没?
}

CompositeDisposable的clear方法内部,实际上就会调用Disposable的dispose方法。
这里我们大致可以猜出一二,Retrofit肯定是重写了dispose方法,在其中把网络请求的call给cancel掉了,这哈被安排得明明白白的。
当然这不是瞎猜啦!具体可以看这位大佬的分析,确实是如此呢。
Retrofit2+Rxjava2如何主动取消网络请求
安排!

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页