上篇文章(DSL形式的基于retrofit、协程的网络请求封装)介绍了,如何基于retorfit、协程去开发一个dsl形式的网络请求,可是封装完后的写法并不足够DSL,有童鞋表示看起来仍是如rxjava同样的链式请求而已。接下来便封装一个标准的DSL网络请求方式。html
DSL是Domain-specific language(领域特定语言)的缩写,维基百科的定义是指的是专一于某个应用程序领域的计算机语言。
这种说法看起来很抽象,其实你们很经常使用的gradle就是DSL最经常使用体现,能够看一下android project中的build.gradle:
java
android{}, dependencies{}这种都是DSL的表现形式,相对于传统的写法更加简洁、表现内容更加明显,如配置文件般的去执行方法,这也是为何推荐DSL写法的缘由。node
如下封装的标准DSL请求方式以下:android
对比以后咱们发现能够说是和gradle基本同样,接下来就展现如何封装。git
class Request<T> {
lateinit var loader: suspend () -> T
var start: (() -> Unit)? = null
var onSuccess: ((T) -> Unit)? = null
var onError: ((String) -> Unit)? = null
var onComplete: (() -> Unit)? = null
var addLifecycle: LifecycleOwner? = null
fun request() {
request(addLifecycle)
}
fun request(addLifecycle: LifecycleOwner?) {
GlobalScope.launch(context = Dispatchers.Main) {
start?.invoke()
try {
val deferred = GlobalScope.async(Dispatchers.IO, start = CoroutineStart.LAZY) {
loader()
}
addLifecycle?.apply { lifecycle.addObserver(CoroutineLifecycleListener(deferred, lifecycle)) }
val result = deferred.await()
onSuccess?.invoke(result)
} catch (e: Exception) {
e.printStackTrace()
when (e) {
is UnknownHostException -> onError?.invoke("network is error!")
is TimeoutException -> onError?.invoke("network is error!")
is SocketTimeoutException -> onError?.invoke("network is error!")
else -> onError?.invoke("network is error!")
}
} finally {
onComplete?.invoke()
}
}
}
}
复制代码
Request对象建立好了,里面放入的参数为方法参数,而不是实体类的参数类型,可是如今使用的时候仍是须要经过new,才能建立request对象调用其request请求方法,那如何才能直接调用request方法呢,这就须要用到kotlin的扩展函数功能:github
inline fun <T> request2(buildRequest: Request<T>.() -> Unit) {
Request<T>().apply(buildRequest).request()
}
inline fun <T> LifecycleOwner.request2(buildRequest: Request<T>.() -> Unit) {
Request<T>().apply(buildRequest).request(this)
}
复制代码
加入上面两个方法以后,咱们就能够直接调用request方法,进行网络请求了:api
fun doHttpRequest2() {
request2<List<UserBean>> {
//addLifecycle 来指定依赖的生命周期的对象
// addLifecycle = {}
start = {
Log.e(TAG, "start doHttpRequest2:currentThreadName:${Thread.currentThread().name}")
}
loader = {
Log.e(TAG, "request doHttpRequest2:currentThreadName:${Thread.currentThread().name}")
RetrofitHelper.getApi().getUserInfo()
}
onSuccess = {
Log.e(TAG, "onSuccess doHttpRequest2:currentThreadName:${Thread.currentThread().name}")
Log.e(TAG, it[0].toString())
}
onError = {
Log.e(TAG, "onError doHttpRequest2:currentThreadName:${Thread.currentThread().name}")
}
onComplete = {
Log.e(TAG, "onComplete doHttpRequest2:currentThreadName:${Thread.currentThread().name}")
}
}
}
复制代码
加入扩展函数以后,这样看起来基本的DSL风格已经有了,可是同gradle对比一看,发现多了一个“=”号,那接下来就想办法去除这个“=”:网络
修改request以下:app
class Request<T> {
private lateinit var loader: suspend () -> T
private var start: (() -> Unit)? = null
private var onSuccess: ((T) -> Unit)? = null
private var onError: ((String) -> Unit)? = null
private var onComplete: (() -> Unit)? = null
private var addLifecycle: LifecycleOwner? = null
infix fun loader(loader: suspend () -> T){
this.loader = loader
}
infix fun start(start: (() -> Unit)?){
this.start = start
}
infix fun onSuccess(onSuccess: ((T) -> Unit)?){
this.onSuccess = onSuccess
}
infix fun onError(onError: ((String) -> Unit)?){
this.onError = onError
}
infix fun onComplete(onComplete: (() -> Unit)?){
this.onComplete = onComplete
}
infix fun addLifecycle(addLifecycle: LifecycleOwner?){
this.addLifecycle = addLifecycle
}
fun request() {
request(addLifecycle)
}
fun request(addLifecycle: LifecycleOwner?) {
GlobalScope.launch(context = Dispatchers.Main) {
start?.invoke()
try {
val deferred = GlobalScope.async(Dispatchers.IO, start = CoroutineStart.LAZY) {
loader()
}
addLifecycle?.apply { lifecycle.addObserver(CoroutineLifecycleListener(deferred, lifecycle)) }
val result = deferred.await()
onSuccess?.invoke(result)
} catch (e: Exception) {
e.printStackTrace()
when (e) {
is UnknownHostException -> onError?.invoke("network is error!")
is TimeoutException -> onError?.invoke("network is error!")
is SocketTimeoutException -> onError?.invoke("network is error!")
else -> onError?.invoke("network is error!")
}
} finally {
onComplete?.invoke()
}
}
}
}
复制代码
之因此有“=”,是由于咱们把执行的方法看成参数传入的,咱们将参数提供一个set方法进行赋值就能够去除“=”,可是调用set方法会出现(),这时咱们增长infix字段修饰,这样在set的时候能够直接去除()替换为{},修改以后调用方法就变成了咱们所须要的DSL风格,与gradle一模一样:async
/**
* 打印结果以下:
*
* LifecycleMainPresenter: start doHttpRequest:currentThreadName:main
* LifecycleMainPresenter: request doHttpRequest:currentThreadName:DefaultDispatcher-worker-2
* LifecycleMainPresenter: onSuccess doHttpRequest:currentThreadName:main
* LifecycleMainPresenter: UserBean(login=null, id=61097549, node_id=MDEwOlJlcG9zaXRvcnk2MTA5NzU0OQ==, avatar_url=null, gravatar_id=null, url=https://api.github.com/repos/JavaNoober/Album, html_url=https://github.com/JavaNoober/Album, followers_url=null, following_url=null, gists_url=null, starred_url=null, subscriptions_url=null, organizations_url=null, repos_url=null, events_url=https://api.github.com/repos/JavaNoober/Album/events, received_events_url=null, type=null, site_admin=false, name=Album, company=null, blog=null, location=null, email=null, hireable=null, bio=null, public_repos=0, public_gists=0, followers=0, following=0, created_at=2016-06-14T06:28:05Z, updated_at=2016-06-14T06:40:26Z)
* LifecycleMainPresenter: onComplete doHttpRequest:currentThreadName:main
*/
fun doHttpRequest2() {
request2<List<UserBean>> {
start {
Log.e(TAG, "start doHttpRequest2:currentThreadName:${Thread.currentThread().name}")
}
loader {
Log.e(TAG, "request doHttpRequest2:currentThreadName:${Thread.currentThread().name}")
RetrofitHelper.getApi().getUserInfo()
}
onSuccess {
Log.e(TAG, "onSuccess doHttpRequest2:currentThreadName:${Thread.currentThread().name}")
Log.e(TAG, it[0].toString())
}
onError {
Log.e(TAG, "onError doHttpRequest2:currentThreadName:${Thread.currentThread().name}")
}
onComplete {
Log.e(TAG, "onComplete doHttpRequest2:currentThreadName:${Thread.currentThread().name}")
}
}
}
复制代码
上篇文章(DSL形式的基于retrofit、协程的网络请求封装)主要是介绍了如何去封装协程+retrofit的网络请求,这篇则是更加***侧重于封装DSL风格***请求,完整的代码已上传至github(CoroutinesHttp),欢迎你们提出更好的建议方法。