fun loadCallback() {
apiCallback({
service.getBanner()
}, {
liveData.value = it//这里是onResponse的回调
}, {
true//这里是onStart的回调
}, onError ={ exception ->
false
})
}
借助函数类型(Any) -> Any来定义请求的不同回调,比如error的回调可以定义为((Exception) -> Boolean)?。接受exception来处理异常,返回bool类型来决定是否继续交给base来继续处理。同时定义成可空类型可以默认交给base出路。但是显而易见的是这种代码书写方式并不如DSL方式的请求美观和可读性高。
关于直接返回LiveData的请求调用示例如下
fun loadLiveData(): LiveData<Result<WanResponse<List>>> {
return apiLiveData(SupervisorJob() + Dispatchers.Main.immediate, timeoutInMs = 2000) {
service.getBanner()
}
}
在V层拿到LiveData后的操作如下:
viewModel.loadLiveData().observe(this, Observer {
when (it) {
is Result.Error -> {
hideLoading()
}
is Result.Response -> {
hideLoading()
it.response.apply {
showToast(Gson().toJson(this))
}
}
is Result.Start -> {
showLoading()
}
else ->{//冗余
}
}
})
显然这种方式的请求更适合轻量化的请求,适合拿到结果直接去渲染view不经过二次数据处理的场景。因为如上图所示在V层处理start、error回调感觉不是很友好,,在reponse中隐藏loading也是比较繁琐。但好处是V层直接可以拿到包含请求数据的LiveData,操作更加便捷。
关于Livedata的封装如下
protected fun apiLiveData(
context: CoroutineContext = EmptyCoroutineContext,
timeoutInMs: Long = 3000L,
request: suspend () -> Response
): LiveData<Result> {
return androidx.lifecycle.liveData(context, timeoutInMs) {
emit(Result.Start())
try {
emit(withContext(Dispatchers.IO) {
Result.Response(request())
})
} catch (e: Exception) {
e.printStackTrace()
emit(Result.Error(e))
} finally {
emit(Result.Finally())
}
}
}
此处的livedata是lifecycle-livedata-ktx,在配置了timeoutInMs后如果没有活跃的observers就会超时自动取消。在IO线程拿到请求的结果后包装成Result,像RxJava那样发射出来即可。为了保证返回的livedata中数据的一致性,start、error也被包装成了Result。
接下来我们以对okhttp和retrofit的请求配置来看下是怎么进行DSL封装的,不多说showcode。
class RequestDsl {
internal var buidOkHttp: ((OkHttpClient.Builder) -> OkHttpClient.Builder)? = null
internal var buidRetrofit: ((Retrofit.Builder) -> Retrofit.Builder)? = null
fun okHttp(builder: ((OkHttpClient.Builder) -> OkHttpClient.Builder)?) {
this.buidOkHttp = builder
}
fun retrofit(builder: ((Retrofit.Builder) -> Retrofit.Builder)?) {
this.buidRetrofit = builder
}
}
首先是DSL的配置类,主要有2个角色,一个是函数类型的buidOkHttp,一个是以buidOkHttp为参数的配置buidOkHttp的高阶函数okHttp。可见buidOkHttp变量是一个可空类型的输入和返回是非空的OkHttpClient.Builder类型的函数,既然是可空类型的我们在初始化调用时就可以选择配置OkHttpClient.Builder与否。
既然输入返回都是OkHttpClient.Builder我们就可以拿到既定的带有初始化配置的OkHttpClient.Builder进行进一部配置,只要最后返回OkHttpClient.Builder就好,同时OkHttpClient.Builder采用了建造者模式我们可以拿到builder引用之后进行二次配置最后原样返回builder的引用。
下面是初始化方法的具体实现
private fun initRequest(okHttpBuilder: OkHttpClient.Builder, requestDSL: (RequestDsl.() -> Unit)? = null) {
val dsl = if (requestDSL != null) RequestDsl().apply(requestDSL) else null
val finalOkHttpBuilder = dsl?.buidOkHttp?.invoke(okHttpBuilder) ?: okHttpBuilder
val retrofitBuilder = Retrofit.Builder()
.baseUrl(this.baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(finalOkHttpBuilder.build())
val finalRetrofitBuilder = dsl?.buidRetrofit?.invoke(retrofitBuilder) ?: retrofitBuilder
this.retrofit = finalRetrofitBuilder.build()
}
这个方法就比较简单,requestDSL定义为可空类型,可以选择配置或者不进行额外配置。此时我们再看一下比较常用的apply方法的如下定义,我们在apply方法中就进入到了泛型T的内部空间,this关键字就指代的是泛型自己 ,可以在内部调用泛型的成员。
public inline fun T.apply(block: T.() -> Unit): T
相似的requestDSL也是和apply方法中的block是一样的类型。一旦选择了进行配置就可以像apply方法一样,在RequestDsl函数内部选择性的调用okHttp或者retrofit方法。那么在关于DSL方式请求调用也和配置请求一样如出一辙不再多说。
internal fun launch(viewModelScope: CoroutineScope) {
viewModelScope.launch(context = Dispatchers.Main) {
onStart?.invoke()
try {
val response = withContext(Dispatchers.IO) {
request()
}
onResponse?.invoke(response)
} catch (e: Exception) {
e.printStackTrace()
onError?.invoke(e)
} finally {
onFinally?.invoke()
}
}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级安卓工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Android移动开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
转存中…(img-rkgUrOVw-1710934832502)]
[外链图片转存中…(img-5JeDinP7-1710934832504)]
[外链图片转存中…(img-3l89Fpf6-1710934832504)]
[外链图片转存中…(img-Fy8dS6xe-1710934832505)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Android)
[外链图片转存中…(img-grBC8koj-1710934832506)]