攜帶狀態的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應用。

相關文章
相關標籤/搜索