Kotlin的好处有很多,其中有一个超级好用的就是扩展方法。
目前来讲,大多数的项目架构都是采用MVP+Rxjava+Dagger2+Retrofit2+AutoDispose+ARouter等等来进行封装的。
今天我们主要来看看对于RxJava的扩展方法,超级好用。
一个是统一的数据解析处理,另一个是统一的线程切换和自动解绑
关于MVP架构的可以看 MVC到MVP的过渡
之前我写过一篇博客,主要是介绍 AutoDispose代替RxLifecycle优雅的解决RxJava内存泄漏问题
还写了 Rxjava2线程调度及Observer的封装 这篇文章,感兴趣的可以先了解一下。
之前的办法我们并没有进行一个统一的封装,导致我们每次在使用IRxJava的时候都要分别调用一下,类似这样
Observable.just("1")
.compose(RxSchedulers.io2main())//切换线程
.autoDisposable(AndroidLifecycleScopeProvider.from(this, Lifecycle.Event.ON_DESTROY))//OnDestory时自动解绑
.subscribe {
}
下面,我们来写一个扩展方法,同时实现线程调度和自动解绑
首先新建一个kotlin文件(注意,后缀名是.kt)
例如RxExtend.kt ,否则可能出现找不到扩展方法的情况,直接写扩展方法即可,不用写在class里面,否则也会找不到
因为线程切换和自动解绑都是针对于Observable的,我们先来看一下Observable的源码
Observable是一个抽象类,我们在该类的基础上进行扩展即可,代码如下
名字可以自己随便起,我这里就用transform(转换)表示了
/*
* 对Observable进行线程调度和生命周期绑定
*
* */
fun Observable.transform(owner: LifecycleOwner): ObservableSubscribeProxy {
return this.compose(RxSchedulers.io2main()).autoDisposable(AndroidLifecycleScopeProvider.from(owner, Lifecycle.Event.ON_DESTROY))
}
扩展方法这样就写好了,其实就是把线程切换和自动解绑封装了下,不过使用扩展方法不会打乱原有的链式结构,Java的话就做不到了。
下面我们来用一用:
Observable.just("1")
.transform(this)
.subscribe {
}
这样一来,我们直接通过调用.transform(this)即可实现线程切换和自动解绑了,是不是更加方便了呢.
正常来讲,我们在开发之前要跟后台定好一个协议,规范返回的数据,
例如:(这里我只是举个例子,实际返回的字段是你跟后台你们自己商量):
我们约定,返回的数据字段只有3个,分别是result,reason,error_code
1. error_code用来确定返回的数据是否正确,0代表成功 -1表示失败
2. reason 表示返回数据时的描述
3. result 返回的具体数据,可能是个json对象,也可能是个json’数组
返回的json结构如下:
{"reason":"成功的返回","result":{},"error_code":0}
或
{"reason":"成功的返回","result":[{},{}],"error_code":0}
对接口返回的数据进行处理是我们经常要做的,比较麻烦的做法就是对每个接口返回的数据生成一个实体类,然后在onNext中进行判断处理。
但是这样一来接口比较多的话就很不好维护了,那我们能不能扩展一个方法,统一对数据进行判断,如果返回正确的话,就把数据传到onNex里,不正确的话就把错误信息传到onError里。
这就好办了,下面我们来声明一个实体类,如下
数据解析我使用的是Gson
其中
result是个泛型类型的,因为我们不知道具体返回的数据到底是什么
/**
* @Description: 服务端返回数据基类
* @author : yzq
* @date : 2018/7/2
* @time : 14:11
*
*/
data class BaseResp(
var reason: String = "", // 成功的返回
var result: T,
@SerializedName("error_code")
var errorCode: Int = 0 // 0
)
RxJava一般都和Retrofit进行配合使用,举个例子,我们要获取新闻列表。
这里我用的是聚合的一个接口,他返回的数据是这样:
{
"reason": "成功的返回",
"result": {
"stat": "1",
"data": [{
"uniquekey": "0bb54602fcc15111afca8452cc127d57",
"title": "口香糖销量下降30%,你一定猜不到原因",
"date": "2019-03-06 12:55",
"category": "头条",
"author_name": "解放网",
"url": "http:\/\/mini.eastday.com\/mobile\/190306125558115.html",
"thumbnail_pic_s": "http:\/\/01imgmini.eastday.com\/mobile\/20190306\/20190306125558_d2b6545a4b6273201218c32c6ffe436a_1_mwpm_03200403.jpg"
}, {
"uniquekey": "c92887585d01563c077c7be7f23dca87",
"title": "《还珠格格》中的演员都老了,网友:五阿哥还是很帅",
"date": "2019-03-06 12:44",
"category": "头条",
"author_name": "北青网",
"url": "http:\/\/mini.eastday.com\/mobile\/190306124440102.html",
"thumbnail_pic_s": "http:\/\/04imgmini.eastday.com\/mobile\/20190306\/20190306124440_bfad5f823d7fcad5e044754e095278ef_1_mwpm_03200403.jpg",
"thumbnail_pic_s02": "http:\/\/04imgmini.eastday.com\/mobile\/20190306\/20190306124440_bfad5f823d7fcad5e044754e095278ef_4_mwpm_03200403.jpg",
"thumbnail_pic_s03": "http:\/\/04imgmini.eastday.com\/mobile\/20190306\/20190306124440_bfad5f823d7fcad5e044754e095278ef_2_mwpm_03200403.jpg"
}]
},
"error_code": 0
}
首先我们要对result返回的数据生成一个实体类(NewBean),如下
data class NewsBean(var stat: String = "", // 1
var data: List = listOf()) {
data class Data(
@Expose
var uniquekey: String = "", // fe1989479c791a1898852edf3b7ed001
@Expose
var title: String = "", // 古装美人饮酒,赵丽颖俏皮,李沁优雅,杨幂豪爽,而她秒杀众人
@Expose
var date: String = "", // 2018-07-13 14:17
@Expose
var category: String = "", // 头条
@Expose
@SerializedName("author_name")
var authorName: String = "", // 北青网
@Expose
var url: String = "", // http://mini.eastday.com/mobile/180713141718664.html
@Expose
@SerializedName("thumbnail_pic_s")
var thumbnailPicS: String = "", // http://05.imgmini.eastday.com/mobile/20180713/20180713141718_bebdf00d5070a17241f48e305bc76f75_3_mwpm_03200403.jpg
@SerializedName("thumbnail_pic_s02")
@Expose
var thumbnailPicS02: String = "", // http://05.imgmini.eastday.com/mobile/20180713/20180713141718_bebdf00d5070a17241f48e305bc76f75_4_mwpm_03200403.jpg
@SerializedName("thumbnail_pic_s03")
@Expose
var thumbnailPicS03: String = "" // http://05.imgmini.eastday.com/mobile/20180713/20180713141718_bebdf00d5070a17241f48e305bc76f75_5_mwpm_03200403.jpg
)
}
请求接口如下,返回一个Observable
interface ApiService {
@POST(ServerContants.Url.index)
@FormUrlEncoded
fun getIndex(@Field(ServerContants.parameter.type) type: String, @Field(ServerContants.parameter.key) key: String): Observable>
}
下面我们来针对这种格式的数据进行统一的解析处理:
这里要注意,是Observable
/*
* 数据转换
*
* */
fun Observable>.dataConvert(): Observable {
return flatMap {
if (it.errorCode == 0) Observable.just(it.result) else Observable.error(Throwable(message = it.reason))
}
下面我们来配合上面的扩展来一起使用
RetrofitFactory.instance.getService(ApiService::class.java)
.getIndex(type, key)
.dataConvert()
.transform(this)
.subscribe {
it.data
}
这样用起来是不是代码很简洁
然后你再结合你自己的项目结构,跟Observer进行一下整合,是非常好用的,并且很好维护的。
下面给出所有代码:
/**
* @description: 线程调度封装
* @author : yzq
* @date : 2018/7/9
* @time : 15:19
*
*/
class RxSchedulers {
companion object {
fun io2main(): ObservableTransformer {
return ObservableTransformer { upstream ->
upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
}
}
}
扩展文件:
/**
* @description: 对RxKotlin的扩展
* @author : yzq
* @date : 2018/7/9
* @time : 15:36
*
*/
/*
* 对Observable进行线程调度和生命周期绑定
*
* */
fun Observable.transform(owner: LifecycleOwner): ObservableSubscribeProxy {
return this.compose(RxSchedulers.io2main()).autoDisposable(AndroidLifecycleScopeProvider.from(owner, Lifecycle.Event.ON_DESTROY))
}
/*
* 数据转换
*
* */
fun Observable>.dataConvert(): Observable {
return flatMap {
if (it.errorCode == ResponseCode.SUCCESS) Observable.just(it.result) else Observable.error(Throwable(message = it.reason))
}
}
同样的,我们还可以对其他类进行扩展,只要是你有需求,感觉代码不简洁的,都可以用扩展来实现。
如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!