2

I have a view model that processes an array of bytes into a somewhat complex array of floats. Part of the data is a timestamp which I've setup as a LiveData type and the observer listens for changes in the timestamp. When a change happens, it gets the new timestamp and also gets the array of floats.

My question is when "value" is set in a LiveData object, are the observers immediately called or does it wait for the surrounding function to complete? In other words, should I make sure to update whatever other data the observer is accessing before setting the "value"?

Also, is this abusing the LiveData mechanism (using it as a flag for a larger change in data)?

  val mTime = MutableLiveData<Double>()
  var mStateDataSet = ArrayList<ArrayList<Float>>()

  fun updateData(rawData: ByteArray) {

    val buffer = ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN)

    val min = (buffer.getInt(4)).toDouble()
    val usec = (buffer.getInt(8)).toDouble()

    val time: Double = min * 60.0 + usec * (1.0 / 1e6)

    // Update the live data....
    mTime.value = time

    // This data is used by the observer of "mTime"
    mStateDataSet[KEY_VOLTAGES] = getSubDataFloat(buffer, NUM_VOLTAGE);
    mStateDataSet[KEY_PRESSURES] = getSubDataFloat(buffer, NUM_PRESSURE);
    mStateDataSet[KEY_LEFT_ANGLES] = getSubDataFloat(buffer, NUM_LEFT_ANGLES);
    mStateDataSet[KEY_RIGHT_ANGLES] = getSubDataFloat(buffer, NUM_RIGHT_ANGLES);
    mStateDataSet[KEY_LEFT_ACCEL] = getSubDataFloat(buffer, NUM_LEFT_ACCEL);
    mStateDataSet[KEY_RIGHT_ACCEL] = getSubDataFloat(buffer, NUM_RIGHT_ACCEL);
    mStateDataSet[KEY_DEBUG] = getSubDataFloat(buffer, NUM_DEBUG);

  }

// Example observer from one of my fragments
    val timeObserver = Observer<Double> { newTime ->
      addDataPoint(mSharedStateDataViewModel.mStateDataSet, newTime)
    }
    mSharedStateDataViewModel.mTime.observe(viewLifecycleOwner, timeObserver)
kkemper
  • 307
  • 2
  • 15
  • 1
    You're updating the LiveData the wrong way. Use `.postValue()`. – Taslim Oseni May 01 '20 at 02:23
  • Can you elaborate why postValue is more appropriate than setValue? – kkemper May 01 '20 at 02:26
  • Here's a Stack Overflow question (and answer) about the difference: https://stackoverflow.com/questions/51299641/difference-of-setvalue-postvalue-in-mutablelivedata – RedBassett May 01 '20 at 02:28
  • I saw that but I couldn't find an answer related to when the observer is actually called. In my case, it's all happening in the main thread (one activity who calls the "updateData" function with whatever fragments attaching observers. I believe setValue is more appropriate for my application though. – kkemper May 01 '20 at 02:32
  • 1
    @kkemper... I assumed you were doing all of this on a background thread. If you are performing these operations on the main thread, use `.setValue()`.Otherwise, use `.postValue()`. – Taslim Oseni May 01 '20 at 02:49

2 Answers2

3

You should update the livedata value with

mTime.postValue(time)

Also, by Tenfour04 comment

postValue will result in the observers being called after this function returns. setValue results in the observers being called before setValue returns, so before the rest of the code in this function.

  • I left out the setting of the observer in my example. I'll add that to be more clear. Could you elaborate on why postValue is better than setValue in this instance? – kkemper May 01 '20 at 02:23
  • 3
    `postValue` will result in the observers being called after this function returns. `setValue` results in the observers being called before `setValue` returns, so before the rest of the code in this function. – Tenfour04 May 01 '20 at 04:31
  • Add that comment to your answer and I'll check it off as the answer! – kkemper May 04 '20 at 23:06
0

Given that the state of the observer's LifeCycleOwner(ie. Activity, Fragment) is at least STARTED and you use the setValue method, the Observer will be notified instantly.

In your case when you do mTime.value = time, this will instantly inform the associated Observer, please note that if you have multiple Observers on the same LiveData object then it may take some time to inform all of them and there may be significant delay between notifications to two different Observers.

If however you use postValue in your example then the Observer will be notified after the enclosing method finishes.

mightyWOZ
  • 7,946
  • 3
  • 29
  • 46