RxJava也能像协程那样优雅的请求网络

RxJava也能像协程那样优雅的请求网络

Retrofit&Coroutines 与 Retrofit&RxJava

两年没写过文章了,一时之间不知道说些什么好…哔…
网络请求框架相信在座的各位都能巴拉巴拉的说出一大堆,但是,我今天要说的不是网络请求框架,今天就来说说被大家吹捧的协程以及比大家抛弃的RxJava的区别吧,以及RxJava到底能不能像协程那样方便快捷。

本篇基于Retrofit2.9.0进行,与之前版本的请求方式略有差别,请注意。

一、创建Retrofit

第一步,Retrofit的配置

object RetrofitManager {

    fun <K> create(clazz: Class<K>) : K = getRetrofit().create(clazz)

    private fun getRetrofit(): Retrofit {
        // 获取retrofit的实例
        return Retrofit.Builder()
             //url必须以 ‘/’ 结尾,不然会报IllegalArgumentException
            .baseUrl(ApiService.BASE_URL)
            .client(getOkHttpClient())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .build()

    }

    private fun getOkHttpClient(): OkHttpClient {
        //添加一个log拦截器,打印所有的log
        val httpLoggingInterceptor = HttpLoggingInterceptor()
        //可以设置请求过滤的水平,body,basic,headers
        httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY

        return OkHttpClient.Builder()
            .addInterceptor(httpLoggingInterceptor) //日志,所有的请求响应度看到
            .connectTimeout(15L, TimeUnit.SECONDS)
            .readTimeout(15L, TimeUnit.SECONDS)
            .writeTimeout(15L, TimeUnit.SECONDS)
            .proxy(Proxy.NO_PROXY)
            .build()
    }
}

二、创建Service接口

本次演示所用的接口来源与 玩android

interface ApiService {

    companion object{
        const val BASE_URL = "https://www.wanandroid.com/"
    }

    @GET("article/list/{page}/json")
    fun getList(
        @Path("page") page: Int
    ) : Observable<HomeListBean>

    @GET("banner/json")
    fun getBannerList(): Call<BannerBean>

    @POST("postxxx/xxx")
    fun postMsg(@Body json : RequestBody) : Observable<BaseBean>
}

好了,我们先回顾下传统的RxJava+Retrofit进行的网络请求。
首先对RxJava进行封装,虽然可能和你们封装的不同但也大同小异。

fun <T : Basexxx> request(){
        check: Boolean = true,
        function: Function<Boolean, ObservableSource<T>>,
        next: Consumer<T>,
        error: Consumer<Throwable> = Consumer {
            finishRefreshorLoadData = true
            errorLiveData.postValue(it)
        }
    ) {
        val disposable = Observable.just(check)
            .subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.io())
            .filter { t -> t }
            .flatMap(function)
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(next, error)
        addSubscription(disposable)
    }

然后请求可能是这样

  request(
            function = Function<Boolean, ObservableSource<xxxBen>>{
            	//网络请求
                model.getList(1)
            },
            next = Consumer{
                liveDataVideo.postValue(it)
            }
        )

没了解协程之前,这样乍看也没什么毛病,中规中矩的,就是不够简便。
再看看协程的网络请求:

  GlobalScope.launch {
            val bean = model.getBannerList().await()
            liveData.postValue(bean)
   }

吸(猛的倒吸吸一口气)。
因为Retrofit是2.9版本的,协程直接封装在Retrofit的内部,作为开发者的我们并不需要去过多的封装,直接就可以进行调用。
两者对比,孰优孰劣一目了然。协程既然能做到这么简便,那RxJava可不可以呢?

三、RxJava重封装

肯定可以啦。
首先我们来分析下网络请求我们所关心的部分:
1.直接处理请求成功结果
2.不关心请求异常
3.界面销毁取消现有的请求
最终封如下,由扩展函数实现

fun <T : BaseBean> Observable<T>.onResult(
        next : (T) -> Unit
    ){
        this onResult Consumer {
            //这里进行返回判断,与后台协定
            if (!TextUtils.equals(it.errorCode,"200")){
                errorLiveData.value = it.errorMsg
                return@Consumer
            }
            next(it)
        }
    }

看看最终的使用结果


    fun getList(){
        //RxJava
         model.getList(0).onResult {
            //做点其他的事情
            //省略其他逻辑代码
            liveData2.value = it
        }

    }

    fun getBannerList(){
        //协程
        GlobalScope.launch {
            val bean = model.getBannerList().await()
            liveData.postValue(bean)
        }

    }

嗯,这就很完美了。如果你的数据请求回调除了post数据之外,没有其他的操作那还可以更加的简单点:

    fun getList(){
        //RxJava
        //没有其他逻辑,直接返回数据
        model.getList(0).onResult(liveData2::setValue)
    }

协程虽然在网络请求有独特之处可以替换RxJava,但RxJava的流式编程也不是协程所能替代的,孰优孰劣难以定义。不知道你喜欢那种呢。 RxJava也能像协程那样优雅的请求网络_第1张图片
结尾附上RxJava的封装代码(Kotlin)

open class BaseViewModel : ViewModel(),IViewModel {

    val errorLiveData: MutableLiveData<String> = MutableLiveData()
    private var compositeDisposable = CompositeDisposable()

    override fun onCreate(owner: LifecycleOwner) {
        //创建
    }

    override fun onDestroy(owner: LifecycleOwner) {
        //销毁
        detachView()
        //移除生命周期监听观察者
        owner.lifecycle.removeObserver(this)
    }

    override fun onLifecycleChanged(owner: LifecycleOwner, event: Lifecycle.Event) {
        //生命周期状态改变
    }

    //泛型可以为  ,也可以为 >
    //此处为Observable的拓展函数,你也可以改为Flowable的拓展函数
    fun <T : BaseBean> Observable<T>.onResult(
        next: Consumer<T>,
        error: Consumer<Throwable> = Consumer {
            errorLiveData.postValue(it.message)
        }
    ) {
        val disposable = this.subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(next, error)
        addSubscription(disposable)
    }

    private infix fun <T : BaseBean> Observable<T>.onResult(
        next: Consumer<T>
    ) {
        this.onResult(next,Consumer {
            errorLiveData.postValue(it.message)
        })
    }

    fun <T : BaseBean> Observable<T>.onResult(
        next : (T) -> Unit
    ){
        this onResult Consumer {
            //这里进行返回判断
            /*if (!TextUtils.equals(it.errorCode,"200")){
                errorLiveData.value = it.errorMsg
                return@Consumer
            }*/
            next(it)
        }
    }


    private fun addSubscription(disposable: Disposable) {
        compositeDisposable.add(disposable)
    }

    private fun detachView() {
        //保证activity结束时取消所有正在执行的订阅
        if (!compositeDisposable.isDisposed) {
            compositeDisposable.clear()
        }
    }
}
Java版

某同学:虽然你说的很好,但是我用的是Java哦,Java有没有办法实现呢?
博主:额。。。这。。。
先看看kotlin的拓展方法转成Java是什么样子的,大概如下:
在这里插入图片描述
RxJava也能像协程那样优雅的请求网络_第2张图片
由此可以看出:
kotlin: (Class)类.Function() 等价于
java的 Function(对象)
等式:Class.(参数…,Function…) ==> Function(对象,参数…,Function…)

所以,以上的代码都可以转换成这样

//Java版
public class BaseViewModel extends ViewModel implements IViewModel {

    public boolean finishRefreshorLoadData = true;
    public MutableLiveData<Throwable> errorLiveData = new MutableLiveData<>();
    private CompositeDisposable compositeDisposable = new CompositeDisposable();

    @Override
    public void onCreate(@NotNull LifecycleOwner owner) {

    }

    @Override
    public void onDestroy(@NotNull LifecycleOwner owner) {
        detachView();
        owner.getLifecycle().removeObserver(this);
    }

    @Override
    public void onLifecycleChanged(@NotNull LifecycleOwner owner, @NotNull Lifecycle.Event event) {

    }

    public <T extends BaseBean> void onResult(
            Observable<T> observable,
            Consumer<T> next,
            Consumer<Throwable> error
    ){
        Disposable disposable = observable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(next, error);
        compositeDisposable.add(disposable);
    }

    public <T extends BaseBean> void onResult(
            Observable<T> observable,
            Consumer<T> next
    ){
        onResult(observable,next,throwable -> {
            errorLiveData.postValue(throwable);
        });
    }
    private void detachView() {
        //保证activity结束时取消所有正在执行的订阅
        if (!compositeDisposable.isDisposed()) {
            compositeDisposable.clear();
        }
    }

}

具体引用如下:

public class JavaViewModel extends BaseViewModel{

    private MainModel model = new MainModel();
    public MutableLiveData<HomeListBean> liveData = new MutableLiveData<>();

    public void getList(){
        onResult(model.getList(0),homeListBean -> {
            //做点其他事情
            liveData.setValue(homeListBean);
        });

        //没有其他操作,直接放回数据
        onResult(model.getList(0),liveData::setValue);
    }
}

某同学:看起来好像没kotlin方便哦。
我:。。。RxJava也能像协程那样优雅的请求网络_第3张图片

项目地址

因为篇幅所限,本文只说RxJava的封装,详细代码就不贴出来了,附上demo的地址,有兴趣的可以去看看。
github: https://github.com/cithrf/RxDemo

你可能感兴趣的:(Android,kotlin)