携带状态的LiveData

前言

在Android MVVM架构中,LiveData做为通知UI更新的桥梁,地位极其重要,能够说是MVVM的核心组件。git

在具体实践中,它每每连接着对数据的异步操做结果。好比在登陆操做中,须要执行异步登陆逻辑,逻辑完成的结果会获得用户信息数据,这个数据可能会赋值给LiveData,用代码表示以下:github

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层中。api

问题

然而异步操做不是当即的,并且有进度,有状态的。咱们的UI极可能须要知道当前的异步数据操做是否正在进行(能够显示进度条),是否已经完成,或者是否失败。markdown

通常咱们能够能这样作:架构

userVM.userData.observe(this, Observer{ 
    if(it==null){
        showFail() //显示请求失败
    }else{
        updateUI() //更新UI
    }
})
showProgress() //登陆以前显示进度条
userVM.login() 

复制代码

虽然咱们也能在代码的某些地方去插入状态展现,但这样的写法太过零碎,不易维护和管理。假设UI代码有几百行,你就会很难找到某个请求的进度条在哪里写着。异步

若是每一个LiveData能携带本身的状态,咱们就能够面向LiveData来进行状态更新,并且能在一个地方集中管理状态,这样就优雅的很。oop

实现

因而咱们能够对LiveData进行扩展,增长一个state字段,表明当前异步操做的状态。因为状态应当是可监听的,因此state也是一个LiveData。代码以下:post

/** * 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层的代码:this

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层对状态的监听变成了这样:spa

//统一管理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应用。

相关文章
相关标签/搜索