-
Notifications
You must be signed in to change notification settings - Fork 2
Status
rongc edited this page Jul 10, 2021
·
1 revision
数据的请求是一个耗时过程,比较友好的做法是在开始请求时显示加载提醒弹窗,结束后在关闭弹窗。在Resource中请求的状态分为以下3种:
- 请求中(LOADING);
- 请求成功(SUCCESS);
- 请求失败(ERROR);
整个远程数据源的请求过程都发生在NetworkBoundResource 中,NetworkBoundResource中有一个名为result的LiveData,类型为Resource,在请求过程中状态变更时都将通过result及时向外发出通知。
在每个请求开始之初到结果返回前,请求的状态都是LOADING。
init {
result.value = Resource.loading(null)
...
}
- Http 相关配置中,除了向HttpProvider提供的CallAdapterFactory外,内部还添加了支持LiveData作为数据源的CallAdapter,在定义后端接口时可以使用LiveData作为方法返回值:
interface WanService {
@GET("banner/json")
fun getBanner(): LiveData<ApiResponse<List<WanBanner>>>
}
但LiveData的直接泛型是ApiResponse而不是List,是因为我们还需要处理异常的情况。
ApiResponse密封类中定义了以下三种情况:
class ApiEmptyResponse<T> : ApiResponse<T>()
data class ApiSuccessResponse<T>(val body: T) : ApiResponse<T>()
data class ApiErrorResponse<T>(val error: Throwable) : ApiResponse<T>()
- ApiEmptyResponse:HTTP 204或无法获取到非空的结果。
- ApiSuccessResponse(body: T):请求正常。
- ApiErrorResponse(error: Throwable):请求发生错误。
在得到请求结果后,LiveDataCallAdapter会把获取到的请求结果按情况封装成上述三种状态并通过LiveData发送出来,结果将会在NetworkBoundResource接收并做进一步转换。
NetworkBoundResource在接收到LiveDataCallAdapter发出请求结果后分析ApiResponse的状态,内容为空和请求成功都视为请求成功,只不过内容为空时使用本地数据。
when (response) {
is ApiSuccessResponse<*> -> {
...
result = Resource.success(response.body)
}
is ApiEmptyResponse<*> -> {
...
result = Resource.success(loadFromDb())
}
is ApiErrorResponse<*> -> {
...
result = Resource.error(response.error, dbSource)
}
}
class RepoSearchFragment : BaseFragment<FragmentListBinding, RepoSearchViewModel>() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.getRepos().observe(viewLifecycleOwner) {
// 在加载中显示弹窗,结束时自动关闭弹窗
showProgressIfLoading(it)
when (it.status) {
Status.LOADING -> {
// 加载中状态, 也可能会有数据(本地的)
it.data
}
Status.SUCCESS -> { it.data }
Status.ERROR -> {
// 加载失败, 错误区分业务错误和网络请求错误,具体可看Http
val error = it.error as? ServiceExeption
if (error?.code == 4403) {
"金币不足".toast()
}
}
}
}
}
}
扩展方法:
- 忽略加载中状态,只接收结果通知
viewModel.getRepos().ignoreLoading(viewLifecycleOwner) {
}
- 只在成功时接收事件
viewModel.getRepos().whenSuccess(viewLifecycleOwner) {
}