10

What is the best way to obtain the last element emitted by a flow without receiving updates.

Question: I use a flow to observe changes in certain shared preferences, but sometimes I want to know the current value of that preference. I always use two functions, one to observe the values in a flow and the other to capture the data directly, is there any way to archive the same behavior with just the observer function?

suspend fun getBreadcrumb(): Breadcrumb =
        withContext(Dispatchers.IO) context@ {
            ...
        }

fun observeBreadcrumb(): Flow<Breadcrumb> {
        ....
    }
cmpeguerog
  • 537
  • 2
  • 7
  • 12

3 Answers3

13

Consider using StateFlow

StateFlow is a new API that was recently added to the coroutines standard library. You can consume it like a regular flow, but it also has a value property that gets the most recent value.

At the moment, the only way to send a new value to a state flow is to update its value property. You can't yet turn a regular flow into a state flow, though there is an open proposal for it.

Let's say you send values to the flow like this:

val breadcrumbs = MutableStateFlow(someValue)

launch {
    while (isActive) {
        waitForSomeCondition()
        breadcrumbs.value = getLatestValue()
    }
}

You can retrieve the latest value whenever you want, for example like this:

launch {
    while (isActive) {
        delay(1000)
        println("Current value is ${breadcrumbs.value}")
    }
}

But you can also collect it like a regular flow, and receive the new value each time it changes:

launch {
    breadcrumbs.collect {
        println("Current value is ${it}")
    }
}

This is an experimental API, so there are likely to be improvements and changes down the line.

Sam
  • 8,330
  • 2
  • 26
  • 51
2

You could expose your Flow as a LiveData with Flow's asLiveData extension function:

class MyViewModel: ViewModel {
    ...
    val myFlowAsLiveData: LiveData<Breadcrumb> = myFlow.asLiveData()
    ...
}

Then you can observe it as usual and if you need its current value just use its value property:

myViewModel.myFlowAsLiveData.value
Glenn Sandoval
  • 3,455
  • 1
  • 14
  • 22
1

Did you try with coroutine function mapLatest

val breadcrumbs = MutableStateFlow(someValue)

breadcrumbs.mapLatest { breadcrumb ->
  println("Latest value is ${breadcrumb}")
}
MeLean
  • 3,092
  • 6
  • 29
  • 43