preface
In the Android MVVM architecture, LiveData plays an extremely important role as a bridge to notify UI updates, which can be said to be the core component of MVVM.
In practice, it often links the results of asynchronous operations on data. For example, in the logon operation, asynchronous logon logic needs to be executed. The result of logon logic is user information data, which may be assigned to LiveData, as shown in the following code:
class UserVM : ViewModel() {
val userData = MutableLiveData<User>()
fun login(a){
viewModelScope.launch {
val result = "http://www.lixiaojun.xin/api/login".http().post<User>().await()
userData.postValue(result)
}
}
}
Copy the code
This kind of code will be abundant in our VM layer.
The problem
Asynchronous operations, however, are not immediate, but progressive and stateful. Our UI will most likely need to know whether the current asynchronous data operation is in progress (which can display a progress bar), has completed, or has failed.
Generally we can do this:
userVM.userData.observe(this, Observer{
if(it==null){
showFail() // Failed to display the request
}else{
updateUI() / / update the UI
}
})
showProgress() // Displays a progress bar before login
userVM.login()
Copy the code
While it is possible to insert a state display at some point in the code, it is too piecemeal to maintain and manage. Assuming hundreds of lines of UI code, you’ll have a hard time finding the progress bar for a particular request.
If each LiveData can carry its own state, we can do status updates for LiveData and centrally manage state in one place, which is elegant.
implementation
We can then extend LiveData by adding a state field that represents the state of the current asynchronous operation. Since state is supposed to be listened on, state is also a LiveData. The code is as follows:
/** * Description: LiveData with status * 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(a) {
state.postValue(State.Idle)
}
fun postLoading(a) {
state.postValue(State.Loading)
}
fun postSuccess(a) {
state.postValue(State.Success)
}
fun postError(a) {
state.postValue(State.Error)
}
fun changeState(s: State) {
state.postValue(s)
}
}
Copy the code
We use StateLiveData to rewrite the VM layer code:
class UserVM : ViewModel() {
val userData = StateLiveData<User>()
fun login(a){
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)
}
}
}
}
Copy the code
The UI layer listens for state like this:
// Manage the state of LiveData
userVM.userData.state.observe(this, Observer{
when(it){
StateLiveData.State.Loading -> showProgress()
StateLiveData.State.Error -> showFail()
/ /... Other state processing
}
})
userVM.userData.observe(this, Observer{
updateUI() // Update the UI directly
})
userVM.login()
Copy the code
recommended
The StateLiveData above is built into my AndroidKTX library: github.com/li-xiaojun/… If you’re developing Android with Kotlin, this library will greatly speed up your development. I am junge, committed to promoting modern Android development, using best practices, the most elegant code to teach you the fastest development of high quality Android applications.