前言
在Android MVVM架构中,LiveData作为通知UI更新的桥梁,地位极其重要,可以说是MVVM的核心组件。
在具体实践中,它往往链接着对数据的异步操作结果。比如在登录操作中,需要执行异步登录逻辑,逻辑完成的结果会得到用户信息数据,这个数据可能会赋值给LiveData,用代码表示如下:
class UserVM : ViewModel() {
val userData = MutableLiveData<User>()
fun login(){
viewModelScope.launch {
val result = "http://www.lixiaojun.xin/api/login".http().post<User>().await()
userData.postValue(result)
}
}
}
复制代码
这样的代码会大量出现在我们的VM层中。
问题
然而异步操作不是立即的,而且有进度,有状态的。我们的UI很可能需要知道当前的异步数据操作是否正在进行(可以显示进度条),是否已经完成,或者是否失败。
一般我们可以能这样做:
userVM.userData.observe(this, Observer{
if(it==null){
showFail() //显示请求失败
}else{
updateUI() //更新UI
}
})
showProgress() //登录之前显示进度条
userVM.login()
复制代码
虽然我们也能在代码的某些地方去插入状态展示,但这样的写法太过零碎,不易维护和管理。假设UI代码有几百行,你就会很难找到某个请求的进度条在哪里写着。
如果每个LiveData能携带自己的状态,我们就可以面向LiveData来进行状态更新,而且能在一个地方集中管理状态,这样就优雅的很。
实现
于是我们可以对LiveData进行扩展,增加一个state
字段,代表当前异步操作的状态。由于状态应当是可监听的,所以state
也是一个LiveData。代码如下:
/**
* Description: 携带状态的LiveData
* Create by lxj, at 2019/3/6
*/
class StateLiveData<T> : MutableLiveData<T>() {
enum class State {
Idle, Loading, Success,Error
}
val state = MutableLiveData<State>()
init {
clearState()
}
fun postValueAndSuccess(value: T) {
super.postValue(value)
postSuccess()
}
fun clearState() {
state.postValue(State.Idle)
}
fun postLoading() {
state.postValue(State.Loading)
}
fun postSuccess() {
state.postValue(State.Success)
}
fun postError() {
state.postValue(State.Error)
}
fun changeState(s: State) {
state.postValue(s)
}
}
复制代码
我们使用StateLiveData改写VM层的代码:
class UserVM : ViewModel() {
val userData = StateLiveData<User>()
fun login(){
viewModelScope.launch {
userData.postLoading()
val result = "http://www.lixiaojun.xin/api/login".http().post<User>().await()
if(result==null){
userData.postError()
}else{
userData.postValueAndSuccess(result)
}
}
}
}
复制代码
而此时UI层对状态的监听变成了这样:
//统一管理LiveData的状态
userVM.userData.state.observe(this, Observer{
when(it){
StateLiveData.State.Loading -> showProgress()
StateLiveData.State.Error -> showFail()
//...其他状态处理
}
})
userVM.userData.observe(this, Observer{
updateUI() //直接更新UI
})
userVM.login()
复制代码
推荐
上面的StateLiveData被内置在我的AndroidKTX类库中:github.com/li-xiaojun/… ,如果你用Kotlin开发Android,这个库将能够大大提高你的开发速度。我是俊哥,致力于推进现代化的Android开发,用最佳的实践,最优雅的代码教你最快速的开发高质量Android应用。