GoogleDemo 学习

最近在看google官方的一个小项目例子,这是 google 为 2018 大会时出的新框架 lifecycle、room、navigation、work 等出的一个项目例子。

https://github.com/googlesamples/android-architecture-components/tree/master/GithubBrowserSample

我看例子看着看着被 retrofit 卡住了,死活找不到它的是如何转换返回值的,快要找吐了,只好整合一下从这例子中学到的东西。

本文仅着重介绍当新框架交互使用时会如何改变项目的开发架构。

 - 项目的分包,大体分为: 三方框架适配、UI、repository(数据)、vo(实体类)

Fragment中使用LiveData的响应式特性,连数据的改变都交给了ViewModel处理,ViewModel却不对页面产生依赖。

//点击“重新加载”刷新页面
binding.callback = object : RetryCallback {
    override fun retry() {
        searchViewModel.refresh()
    }
}
// liveData 更新时刷新列表
searchViewModel.results.observe(this, Observer { result ->
    binding.searchResource = result //视图 的加载中,加载失败,等状态转交 viewModel 管理
    binding.resultCount = result?.data?.size ?: 0
    adapter.submitList(result?.data)
    binding.executePendingBindings()
})

viewModel 当然依赖于 repostory 来拿取数据,但正如 viewModel 不依赖 view,而转为都依赖 liveData 那样,repostory 对 viewModel 的数据请求回调也由 liveData 完成,防止了内存泄露。

/**搜索结果列表,监听搜索内容,随搜索关键字触发*/
val results: LiveData<Resource<List<Repo>>> = Transformations
        .switchMap(query) { search -> // 关键字改变时,重新搜索
            if (search.isNullOrBlank()) {
                AbsentLiveData.create()
            } else {
                repoRepository.search(search) //拿取数据
            }
        }

上面代码例子的 results 是直接被 View 所监听的,一旦触发,View 的列表便会随之改变。而 query 是关键字,一旦关键字改变,就会调用 repository.search(关键字) 重新请求数据,形成了: 关键字改变 -> 重新请求数据 -> 视图列表刷新,这样的事件链。

而关于 数据仓库(repository)部分,则是使用模板模式封装好请求逻辑后,将事件接入的。

//先将数据切为 - 正在加载数据,由于result没有任何观察者,不会触发任何视图改变
result.value = Resource.loading(null)
//从数据库拿取数据 非null
@Suppress("LeakingThis")
val dbSource = loadFromDb()
//数据库查询是异步的,此时 result.value 可能为 null,所以使用 source 让它查到结果时才触发 Callback
result.addSource(dbSource) { data -> // result 即是被viewModel观察的结果
    //第一次查到结果就够了,移除监听
    result.removeSource(dbSource)
    //判断是否需要从网络拿取数据,
    if (shouldFetch(data)) {
        fetchFromNetwork(dbSource)
    } else {
        //直接使用数据库查询的数据
        result.addSource(dbSource) { newData ->
            setValue(Resource.success(newData))
        }
    }
}
================ 模板中的变化部分 ==============
/**网络请求失败*/
protected open fun onFetchFailed() {}

/**保存网络拿到的数据到数据库*/
@WorkerThread
protected abstract fun saveCallResult(item: RequestType)

/**判断数据是否需要从网络拿取 [data]-送数据库查到的数据 */
@MainThread
protected abstract fun shouldFetch(data: ResultType?): Boolean

/**从数据库查询数据 return-数据库数据LiveData */
@MainThread
protected abstract fun loadFromDb(): LiveData<ResultType>

/**调用的接口*/
@MainThread
protected abstract fun createCall(): LiveData<ApiResponse<RequestType>>

 数据请求事件在 init 中进行编写: 请求数据 = 查询数据库 -> 判断是否需要重新从网络请求数据 -> (请求网络数据+保存在数据库+从数据库拿取数据) or 从数据库拿取数据;

最终是借助 Room(数据库框架)与LiveData可交互 的特性,将 View 的列表数据改变 绑定到 数据库数据改变 。

 

有一些模块特别让我眼前一亮:

databinding封装了加载画面,封装的程度达到变量只有 状态(无,加载中,加载失败)、重试点击回调。这下使用起来很方便,状态作为livedata提取出来,交给仓库类管理。以往的网络请求是 启动加载中视图,开启请求,在请求后关闭加载中视图。而现在交由 Model 部分管理。

数据加载状态封装,不同于以往的 将 数据加载状态与数据分开写,项目例子直接用 数据加载状态类,持有数据的引用,如此一来数据状态与数据就将一起使用,便于判断数据与在View中做出改变。

网络请求的封装,最近我产生了一个如何封装网络请求更好的疑问,而这demo毫无疑问给了我启发,(post/get、url、参数类型、响应类型)这些是一起的变量,可以封装在一个模块。(结果处理,数据库缓存、数据拿取)这些是互相独立的模块。在项目例子中,对网络请求的使用简单到:传入一个Retrofit接口,拿到LiveData。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值