0
  • Layout
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="viewmodel"
            type="com.example.MyViewModel" />
    </data>
<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/llNoDataLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:executionResult="@{viewmodel.state}"/>
</layout>
  • ViewModel
class MyViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle
): ViewModel(){
    private val _state = MutableStateFlow<ExecutionResult<List<glucometerData>>>(ExecutionResult.idle())
    val state: StateFlow<ExecutionResult<List<glucometerData>>> = _state

}
  • **Binding Adapter **
@BindingAdapter("executionResult")
fun View.visibility(state: ExecutionResult<List<Data>>?){
    println("View.visibility:: Execution Result: state: $state")
    when(state){
        is ExecutionResult.Data -> {
            this.isVisible = state.data.isNotEmpty()

        }
        is ExecutionResult.Error -> {

        }
        is ExecutionResult.Idle -> {

        }
        is ExecutionResult.Loading -> {
            when(state.isLoading){
                true -> this.isVisible = false
            }
        }
    }
}

I am getting data from the repository. It will set Execution result in the following order: progress = true, data, progress = false. In the binding adpater, I am getting only the Idle state and progress = false. Rest of the state in between is getting skipped. Same thing is happening if I replace StateFlows with LiveData

Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
a.r.
  • 565
  • 1
  • 6
  • 18
  • That's how LiveData & MutableStateFlow work in general, an observer only sees the latest state, and the observer may not see intermediate states from a fast producer. Relying on intermediate states is not a valid pattern in these cases. – Uli Sep 22 '21 at 15:25
  • Can you provide link to the documentation? – a.r. Sep 22 '21 at 17:25
  • Instead of imposing state from the outside, try observing outside state from your Viewmodel. That's the general architectural advice I can offer, you may need to read up on these topics a bit. – Uli Sep 22 '21 at 22:15
  • Also, process the data in your Viewmodel, not in the Bindingadapter – Uli Sep 22 '21 at 22:50
  • I am processing in the ViewModel itself now. But as far as I remember few versions back LiveData doesn't have any such issue. Might be internal implementations have been changed. I am curious to know if this behavior is supported by some android documentations. – a.r. Sep 23 '21 at 04:21
  • Also if I collect the same StateFlow in fragment, I am getting all the states. – a.r. Sep 23 '21 at 04:23
  • You might consider looking at the LiveData source code and/or writing a number of tests with different timings, in particular a fast producer with a slow consumer. I can't provide any further help, but it sounds like you're on the right track. – Uli Sep 23 '21 at 11:56

0 Answers0