2
votes

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)
2
You're updating the LiveData the wrong way. Use .postValue(). - Taslim Oseni
Can you elaborate why postValue is more appropriate than setValue? - kkemper
Here's a Stack Overflow question (and answer) about the difference: stackoverflow.com/questions/51299641/… - RedBassett
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
@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

2 Answers

3
votes

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.

0
votes

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.