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)
}
}
嗯,这就很完美了。
协程虽然在网络请求有独特之处可以替换RxJava,但RxJava的流式编程也不是协程所能替代的,孰优孰劣难以定义。不知道你喜欢那种呢。
结尾附上RxJava的封装代码
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) {
//生命周期状态改变
}
//泛型可以为 <T : BaseBean> ,也可以为 <T : List<BaseBean>>
//此处为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()
}
}
}
项目地址
因为篇幅所限,本文只说RxJava的封装,详细代码就不贴出来了,附上demo的地址,有兴趣的可以去看看。
github: https://github.com/cithrf/RxDemo