携带状态的LiveData

前言

在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应用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值