其他分享
首页 > 其他分享> > 两种方式封装Retrofit+协程,实现优雅快速的网络请求,逆袭面经分享

两种方式封装Retrofit+协程,实现优雅快速的网络请求,逆袭面经分享

作者:互联网

override fun onSuccess(data: List?) {

}

override fun one rror() {

}

})

mViewModel.wxArticleLiveData.observeState(this) {

onSuccess { data: List? ->

}

onError {

}

}

既然是用Kotlin了,就不要用Java的方式写接口回掉了,DSL表达式不香么?

提供两种方式实现:

两种方式设计思路在解耦这一块存在差异,看具体需求,没有谁好谁差,依照自己的项目,哪个更方便用哪个。

基于官方架构的封装:

一、封装一

=====

Activity中的代码示例


点击请求网络

mViewModel.getArticleData()

设置监听,只监听成功的结果,使用默认异常处理

mViewModel.wxArticleLiveData.observeState(this) {

onSuc

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

cess { data ->

Log.i(“wutao”,“网络请求的结果是:$data”)

}

}

如果需要单独处理每一个回调

这些回调都是可选的,不需要可不实现

mViewModel.wxArticleLiveData.observeState(this) {

onSuccess { data ->

Log.i(“wutao”,“网络请求的结果是:$data”)

}

onEmpty{

Log.i(“wutao”, “返回的数据是空,展示空布局”)

}

onFailed {

Log.i(“wutao”, “后台返回的errorCode: $it”)

}

onException { e ->

Log.i(“wutao”,“这是非后台返回的异常回调”)

}

onShowLoading {

Log.i(“wutao”,“自定义单个请求的Loading”)

}

onComplete {

Log.i(“wutao”,“网络请求结束”)

}

}

请求自带Loading

很多网络请求都需要Loading,不想每次都写onShowLoading{}方法,也so easy。

mViewModel.wxArticleLoadingLiveData.observeState(this, this) {

onSuccess { data ->

Log.i(“wutao”,“网络请求的结果是:$data”)

}

}

observeState()第二个方法传入ui的引用就可,这样单个网络请求之前会自动加载Loading,成功或者失败自动取消Loading。

上面代码都是Activity中,我们来看下ViewModel中。

ViewModel中代码示例


class MainViewModel{

private val repository by lazy { WxArticleRepository() }

val wxArticleLiveData = StateLiveData<List>()

fun requestNet() {

viewModelScope.launch {

repository.fetchWxArticle(wxArticleLiveData)

}

}

}

很简单,引入对应的数据仓库Repo,然后使用协程执行网络请求方法。来看下Repo中的代码。

Repository中代码示例


class WxArticleRepository : BaseRepository() {

private val mService by lazy { RetrofitClient.service }

suspend fun fetchWxArticle(stateLiveData: StateLiveData<List>) {

executeResp(stateLiveData, mService::getWxArticle)

}

}

interface ApiService {

@GET(“wxarticle/chapters/json”)

suspend fun getWxArticle(): BaseResponse<List>

}

获取一个Retrofit实例,然后调用ApiService接口方法。

封装一的优势

======

封装一的不足

======

封装一的核心思想是:一个LiveData贯穿整个网络请求链。这是它的优势,也是它的劣势。

Repository是做一个数据仓库,项目中获取数据的方式都在这里同意管理,网络获取数据只是其中一个方式而已。

如果想加一个从数据库或者缓存中获取数据,封装一想改都不好改,如果强制改就破坏了封装,侵入性很大。

针对封装一的不足,优化出了封装二。

二、封装二

=====

思路

Activity中代码


// 请求网络

mViewModel.login(“username”, “password”)

// 注册监听

mViewModel.userLiveData.observeState(this) {

onSuccess {data ->

mBinding.tvContent.text = data.toString()

}

onComplete {

dismissLoading()

}

}

observeState()中不再需要一个ui引用了。

ViewModel中


class MainViewModel {

val userLiveData = StateLiveData<User?>()

fun login(username: String, password: String) {

viewModelScope.launch {

userLiveData.value = repository.login(username, password)

}

}

}

通过livedata的setValue或者postValue方法将数据发送出去。

Repository中


suspend fun login(username: String, password: String): ApiResponse<User?> {

return executeHttp {

mService.login(username, password)

}

}

Repository中的方法都返回请求结果,并且方法参数不需要livedata。Repository完全可以独立出来了。

针对多数据源


// WxArticleRepository

class WxArticleRepository : BaseRepository() {

private val mService by lazy {

RetrofitClient.service

}

suspend fun fetchWxArticleFromNet(): ApiResponse<List> {

return executeHttp {

mService.getWxArticle()

}

}

suspend fun fetchWxArticleFromDb(): ApiResponse<List> {

return getWxArticleFromDatabase()

}

}

// MainViewModel.kt

private val dbLiveData = StateLiveData<List>()

private val apiLiveData = StateLiveData<List>()

val mediatorLiveDataLiveData = MediatorLiveData<ApiResponse<List>>().apply {

this.addSource(apiLiveData) {

this.value = it

}

this.addSource(dbLiveData) {

this.value = it

}

}

可以看到,封装二更符合职责单一原则,Repository单纯的获取数据,ViewModel对数据进行处理和发送。

三、实现原理

======

数据来源于鸿洋大神的玩Android 开放API

回数据结构定义:

{

“data”: …,

“errorCode”: 0,

“errorMsg”: “”

}

封装一和封装二的代码差距很小,主要看封装二。

定义数据返回类


open class ApiResponse(

open val data: T? = null,

open val errorCode: Int? = null,

open val errorMsg: String? = null,

open val error: Throwable? = null,

) : Serializable {

val isSuccess: Boolean

get() = errorCode == 0

}

data class ApiSuccessResponse(val response: T) : ApiResponse(data = response)

class ApiEmptyResponse : ApiResponse()

标签:Loading,封装,请求,val,面经,Repository,协程,data,逆袭
来源: https://blog.csdn.net/m0_64604893/article/details/121863851