简体   繁体   中英

How to observe Emited LiveData with MVVM

I am struggling to understand how to handle emitted liveData. I have written four different examples of liveData here,

class MainViewModel : ViewModel() {
    val viewModelValue = MyRepo.liveValue
    fun viewModelGetNextValue(){
        MyRepo.getNextValue()
    }

    val viewModelSquareValue = MyRepo.squareLiveValue
    fun viewModelGetSquareValue(x:Int){
        MyRepo.getSquareValue(x)
    }

    val viewModelEmitValue = MyRepo.emitLiveValue

    lateinit var viewModelEmitFunctionValue:LiveData<String>
    fun viewModelEmitLiveFunction(x:Int){
        viewModelEmitFunctionValue = MyRepo.emitLiveFunction(x)
    }
}

object MyRepo{
    var value = 1

    val liveValue = MutableLiveData<Int>()
    fun getNextValue(){
        liveValue.postValue(++value)
    }

    val squareLiveValue = MutableLiveData<Int>()
    fun getSquareValue(x:Int){
        squareLiveValue.postValue(x*x)
    }

    val emitLiveValue = liveData {
        emit("First Emit")
        delay(2000)
        emit("second value")
    }

    fun emitLiveFunction(x:Int) = liveData {
        emit("value: $x")
        delay(2000)
        emit("square: ${x*x}")
    }
}

And part of the Fragment code is,

        viewModel.viewModelValue.observe(viewLifecycleOwner, Observer {
            Toast.makeText(activity, "$it", Toast.LENGTH_SHORT).show()
        })
        viewModel.viewModelSquareValue.observe(viewLifecycleOwner, Observer {
            Toast.makeText(activity, "$it", Toast.LENGTH_SHORT).show()
            viewModel.viewModelSquareValue.removeObservers(viewLifecycleOwner)
        })
        viewModel.viewModelEmitValue.observe(viewLifecycleOwner, Observer {
            Toast.makeText(activity, it, Toast.LENGTH_SHORT).show()
        })

        button1.setOnClickListener { viewModel.viewModelGetNextValue() }
        button2.setOnClickListener { viewModel.viewModelGetSquareValue(++x) }
        button3.setOnClickListener {
            viewModel.viewModelEmitLiveFunction(++x)
            viewModel.viewModelEmitFunctionValue.observe(viewLifecycleOwner, Observer {
                Toast.makeText(activity, it, Toast.LENGTH_SHORT).show()
            })
        }

First Two examples of LiveData ( viewModelValue and viewModelSquareValue ) is easy to observe. and can be invoked with the button's click listener. The third livedata viewModelEmitValue where I have used emit automatically shows the value.

What do I have to do if I want those values after a button being clicked? Do I just have to write the observer code within the click listener?

The last liveData viewModelEmitFunctionValue is working. But is it the only way (using lateinit var ) to get the value if I want to get it after I click a button?

The last liveData viewModelEmitFunctionValue is working. But is it the only way (using lateinit var) to get the value if I want to get it after I click a button?

In this way you are creating observers for each button click, adding an additional Toast every other click. Good news is that you are creating LiveData instance as well with every click so previous observers cleaned up. But it's a bit of a messy approach.

val emitLiveValue = liveData { is not a lazy way to declare a LiveData, so once you Repo is initialized it starts executing code inside liveData{}

In case of fun emitLiveFunction(x:Int) = liveData { you are creating LiveData only at the moment of calling the function, so that's why it works well.

My suggestion is to store x value in live data and calculate emitLiveFunction on each change of it. You can achieve it using Transformations.switchMap

class MainViewModel : ViewModel() {
...
  private val x = MutableLiveData<Int>()
  val functionResult = x.switchMap { MyRepo.emitLiveFunction(it) }

  fun viewModelEmitLiveFunction(x:Int) { 
      this.x.postValue(x)
  }
}

Now you can add an observer to functionResult right after activity created and calling viewModelEmitLiveFunction(x) on button 3 click you will initiate repo function execution with new value x

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM