内容简介:最近很不顺利,每天晚上回家都打不到车!之前晚上10点很容易叫到车,不是说好996福报的么?难不成大家都在享受福报,司机都忙不过来了?管他呢,就算打不到车,我也要学习,毕竟一天不学习我浑身难受!之前几篇文章聊过JatPack中LiveData和ViewModel的基本使用和原理。历史文章如下:
最近很不顺利,每天晚上回家都打不到车!之前晚上10点很容易叫到车,不是说好996福报的么?难不成大家都在享受福报,司机都忙不过来了?管他呢,就算打不到车,我也要学习,毕竟一天不学习我浑身难受!
之前几篇文章聊过JatPack中LiveData和ViewModel的基本使用和原理。历史文章如下:
今天咱们继续看一下实际的应用。实战篇初步打算俩篇文章,分别是:
- Google Sample写的一个简易的网络框架:NetworkBoundResource。
- MVVM项目实战
NetworkBoundResource篇
一、什么是NetworkBoundResource
首先来说一下 NetworkBoundResource是什么,其实 NetworkBoundResource单纯就是一个类,全类也就100+行,但是这个类结合LiveData,创造了极为便利的常用网络功能,比如:
- 不请求网络,直接使用缓存
- 自定义策略,是否请求网络
- 网络加载失败后使用缓存
- 返回类型处理
- 等等
不说了,直接上代码!先看一段这个类的使用:
// UI层直接调用这个方法,拿到LiveData,监听即可(当然,正常来说需要设计一番,UI层直接粗暴的调用,不大合适~)
fun loadData(queryId: Long = -1): LiveData<Resource<DataResp>> {
return object :
NetworkBoundResource<DataResp, DataResp>(
appExecutors
) {
override fun saveCallResult(item: DataResp) {
// 此方法,在网络数据回来后调用,我们可以做一些持久化的逻辑
}
override fun shouldFetch(data: DataResp?): Boolean {
// 自己控制,是否触发网络请求,如果false,则调用loadFromDb()
return isUseNetWork
}
override fun loadFromDb(): LiveData<MusicStoreMainResp> {
// 自己实现从非网络环境下获取数据的逻辑(比如内存,DB)
return data
}
override fun createCall(): LiveData<ApiResponse<DataResp>> {
return
}.asLiveData()
}
复制代码
我们可以看到,4个实现方法,分别对应了:
- 数据返回后的持久化回调
- 是否走网络请求
- 从本地请求数据(业务方自己实现)
- 网络请求(业务方自己实现)
对于我们业务方来说,只需要调用 oadData() ,然后 observe() ,返回的 LiveData 即可。
当然对应的正真的业务请求需要自己实现
二、NetworkBoundResource流程图
也就是说 NetworkBoundResource 帮我们抽象了一系列的逻辑,而且,它的实现非常的短,让我们来看一下代码, NetworkBoundResource 做了什么?能帮我们如此简单的完成这么多逻辑?
三、NetworkBoundResource源码实现
上源码:
详细使用可以参考Google Sample: github.com/googlesampl…
abstract class NetworkBoundResource @MainThread constructor(private val appExecutors: AppExecutors) {
//这里是业务能拿到的数据,livedata
//MediatorLiveData不多说了吧,上文已经介绍过了
private val result = MediatorLiveData<Resource<ResultType>>()
init {
// 先发一个LOADIN,通知业务放处理LOADING态
result.value = Resource.loading(null)
@Suppress("LeakingThis")
//db也是一个数据源
val dbSource = loadFromDb()
result.addSource(dbSource) { data ->
//db的第一次回调,是用来判断数据有效期的
result.removeSource(dbSource)
//是否有效,业务自行定义(请求网络的策略)
if (shouldFetch(data)) {
fetchFromNetwork(dbSource)
} else {
//数据有效,重新观察一次,观察者会立马收到一次回调{Source.plug}
result.addSource(dbSource) { newData ->
setValue(Resource.success(newData))
}
}
}
}
@MainThread
private fun setValue(newValue: Resource<ResultType>) {
if (result.value != newValue) {
result.value = newValue
}
}
private fun fetchFromNetwork(dbSource: LiveData<ResultType>) {
val apiResponse = createCall()
// 将dbsource重新add,它将快速地发送其最新值。db有数据,但是过期了,先回调给业务展示
// 这里保证了,LOADING态时也可以拿到数据,并展示给用户。
result.addSource(dbSource) { newData ->
setValue(Resource.loading(newData))
}
result.addSource(apiResponse) { response ->
//这里又是用来控制流程,移除,避免数据乱入,而且设计者不让add重复的source
result.removeSource(apiResponse)
result.removeSource(dbSource)
when (response) {
is ApiSuccessResponse -> {
appExecutors.diskIO.execute {
//数据回来先存缓存,这样我们下次请求过来时,可能保证LOADING态拿到的数据是最新的。
saveCallResult(processResponse(response))
appExecutors.mainThread.execute {
// 原注释:we specially request a new live data,
// otherwise we will get immediately last cached value,
// which may not be updated with latest results received from network.
//重新从库里面读取
result.addSource(loadFromDb()) { newData ->
setValue(Resource.success(newData))
}
}
}
}
is ApiEmptyResponse -> {
appExecutors.mainThread.execute {
// reload from disk whatever we had
result.addSource(loadFromDb()) { newData ->
setValue(Resource.success(newData))
}
}
}
is ApiErrorResponse -> {
onFetchFailed()
result.addSource(dbSource) { newData ->
setValue(Resource.error(response.exception, newData))
}
}
}
}
}
// 业务方自行处理的抽象方法
protected open fun onFetchFailed() {}
fun asLiveData() = result as LiveData<Resource<ResultType>>
@WorkerThread
protected open fun processResponse(response: ApiSuccessResponse<RequestType>) = response.data
@WorkerThread
protected abstract fun saveCallResult(item: RequestType)
@MainThread
protected abstract fun shouldFetch(data: ResultType?): Boolean
@MainThread
protected abstract fun loadFromDb(): LiveData<ResultType>
@MainThread
protected abstract fun createCall(): LiveData<ApiResponse<RequestType>>
}
复制代码
尾声
这一部分,建议大家好好理解一下。因为真的真的真的很好用,它的设计结合了 LiveData 一系列的巧妙应用。理解之后,大家绝对会对 LiveData 有更加深入的理解,并且在接下来的MVVM中,也会感受到这其中的巧妙和爽快。
接下来的实战篇,基本就是结合 NetworkBoundResource 的MVVM设计,希望能够给大家在业务架构上带来帮助。
我是一个应届生,最近和朋友们维护了一个公众号,内容是我们在从应届生过渡到开发这一路所踩过的坑,以及我们一步步学习的记录,如果感兴趣的朋友可以关注一下,一同加油~
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 「Flask实战」鱼书项目实战一
- 「Flask实战」鱼书项目实战三
- 「Flask实战」鱼书项目实战四
- 「Flask实战」鱼书项目实战六
- RocketMQ实战系列从理论到实战
- 「Flask实战」flask鱼书项目实战二
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Ordering Disorder
Khoi Vinh / New Riders Press / 2010-12-03 / USD 29.99
The grid has long been an invaluable tool for creating order out of chaos for designers of all kinds—from city planners to architects to typesetters and graphic artists. In recent years, web designers......一起来看看 《Ordering Disorder》 这本书的介绍吧!