对比:
传统的网络请求框架流程(以登录操作为例):
Java:
AccountCall.Login(userName,password,new Callback<LoginResponse>{
onBefore(){
...
执行网络请求之前的行为
...
}
onSuccess(LoginResponse response){
...
网络请求成功
...
}
onFail(String errorMsg){
...
网络请求失败
...
}
onAfter(){
...
执行网络请求之后的行为
...
}
});
Kotlin:
AccountCall.Login(userName,password,object: Callback<LoginResponse>(){
onBefore(){
...
执行网络请求之前的行为
...
}
onSuccess(response: LoginResponse){
...
网络请求成功
...
}
onFail(errorMsg: String){
...
网络请求失败
...
}
onAfter(){
...
执行网络请求之后的行为
...
}
})
Kotlin网络请求DSL:
AccountCall.Login(userName,password).before(
...
执行网络请求之前的行为
...
}.success{
it ->
...
网络请求成功
...
}.fail{
it ->
...
网络请求失败
...
}.after{
...
执行网络请求之后的行为
...
}
如果只需要成功的结果,则只需调用成功的函数即可:
AccountCall.Login(userName,password).success{
it ->
...
网络请求成功
...
}
实现:
okhttp+retrofit+rxjava作为网络请求的老三样,一直是很多开发者网络请求的方案,但rxjava作为一款强大的异步框架只用来执行网络请求的线程切换未免也太过大材小用了,所以这次不用rxjava,而是用自定义的Caller,那么就需要实现自定义的CallAdapter和CallAdapterFactory,下面贴出代码
DSL基类
abstract class WhtBaseRequest<R> {
var funBefore = {}
var funSuccess = {response:R -> Unit}
var funFail = {failMsg: String -> Unit}
var funAfter = {}
open fun before(onBefore:() -> Unit) : WhtBaseRequest<R> {
funBefore = onBefore
return this
}
open fun success(onSuccess:(R) -> Unit) : WhtBaseRequest<R> {
funSuccess = onSuccess
return this
}
open fun fail(onFail: (String) -> Unit): WhtBaseRequest<R> {
funFail = onFail
return this
}
open fun after(onAfter: () -> Unit): WhtBaseRequest<R> {
funAfter = onAfter
return this
}
abstract fun isSuccess(response: R): Boolean
abstract fun failMessage(response: R) : String
}
自定义Call,通过协程实现异步请求
class WhtCall<R>(rawCall: Call<R>) {
var rawCall = rawCall
/**
* 异步请求
*/
fun <W : WhtBaseRequest<R>> enqueue(whtRequest: W) : W{
MainScope().launch {
whtRequest.funBefore?.invoke()
val result = withContext(Dispatchers.IO){
try {
val response: Response<R> = rawCall?.execute() as Response<R>
response
}catch (t: Throwable){
t
}
}
when(result){
is Throwable -> whtRequest?.funFail?.invoke(result?.message ?: "未知异常")
is Response<*> -> {
val body = result.body() as R
if(whtRequest.isSuccess(body)){
whtRequest.funSuccess?.invoke(body)
}else{
whtRequest.funFail?.invoke(whtRequest.failMessage(body))
}
}
}
whtRequest.funAfter?.invoke()
}
return whtRequest
}
/**
* 同步请求
*/
fun execute() : R?{
val response: Response<R> = rawCall?.execute() as Response<R>
return response?.body()
}
}
自定义CallAdapter
class WhtCallAdapter<R> constructor(type: Type,myClz : Class<R>) : CallAdapter<R,WhtCall<R>> {
val responseType = type
override fun adapt(call: Call<R>) = WhtCall(call)
override fun responseType() = responseType
}
自定义CallAdapterFactory
class WhtCallAdapterFactory : CallAdapter.Factory() {
companion object{
fun create() = WhtCallAdapterFactory()
}
override fun get(
returnType: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): CallAdapter<*, *>? {
val rawType = getRawType(returnType)
return when(rawType){
WhtCall::class.java -> {
val responseType = getParameterUpperBound(0, returnType as ParameterizedType)
val responseClz = getRawType(responseType)
WhtCallAdapter(responseType,responseClz)
}
else -> null
}
}
}
以上就是网络请求DSL的核心代码,可以通过继承WhtBaseRequest来自定义判断请求结果是否成功的规则和结果为失败的错误信息,也可以在请求流程中做通用的动作,比如说请求之前弹出loading,请求完成后消失。可以写一个默认的子类:
DefaultRequest
class DefaultRequest<R: BaseResponse>: WhtBaseRequest<R>() {
override fun isSuccess(response: R) = CodeUtil.isSuccess(response)
override fun failMessage(response: R) = response?.message ?: "未知异常"
}
而请求封装的业务层代码也很简单,比如获取app配置的接口请求就可以这么写:
基础配置请求
/**
* 获取基础配置
*/
fun getConfig() = HttpUtils.instance.createApi(BaseApi::class.java).getConfig().enqueue(DefaultRequest())
由于对协程的使用还是不太熟悉,所以没有绑定组件的生命周期,很有可能造成内存泄漏的发生,还有很大的优化空间。