0

In the proccess of migration I found out some things that I would like to comment out with people who have good knowledge about this. To be honest, I am not master of flow, used livedata for long time, so now I would like to figure out as much as I can about flow from the start.

While working with it I found out that most of the time instead of liveData, I would use StateFlow (much much more than SharedFlow). But what Are the cases of using SharedFlow I asked myself. I came across this one totally by accident.

I had livedata in situation where I emitted boolean value when user long clicks on the row of recyclerView. click would post true value and I would react in my fragment. Now I tried to change it in stateflow:

val dataInserted: MutableStateFlow<Boolean> = MutableStateFlow(false)
// more code
dataInserted.emit(true)

And in my fragment, I collect data:

CoroutineScope(Dispatchers.Main).launch {
        mainViewModel.dataInserted.collect {
           // doSomething()
        }
    }

but I found out that my doSomething() function is called only one time. With livedata this worked well, but with stateFlow, I guess it needs different value to react. If you send true 2 times, or 3 times, it will react only one time since it gets the same value. Is my assumption true on this one?

Anyways after this I decided to implement Sharedflow here and it works well. Why does this work with sharedFlow and not with stateFlow. Does SharedFlow drop value after it gets collected, so after it collets same value again, it can react again. this is my second assumption and I would like someone to confirm or deny me and explain if I am wrong.

Also are state and shared flow enough to completely replace whole livedata. Is there anything else or these 2 guys can solve all my needs. Thanks in advance

Kratos
  • 681
  • 1
  • 13
  • 30
  • 1
    `StateFlow` will not emit a duplicate value, `SharedFlow` does not a `value` property. Also, you should be using the `viewLifecycleOwner.lifecycleScope` to observe the `Flow` in your fragment. – Darshan Sep 07 '22 at 12:37
  • @DarShan so SharedFlow never has value. It just collects emitted value, does something with it and drops/forgets about it immediately? – Kratos Sep 07 '22 at 12:39
  • `SharedFlow` can buffer previous values for new collectors if they are defined. It can be configured how many previous values to be emitted to new collectors. – Darshan Sep 07 '22 at 12:41
  • 2
    SharedFlow has as many values as you set with the `replay` constructor parameter. But you can only see them by collecting. By the way, like mentioned above, use `viewLifecycleOwner`. This: (`CoroutineScope(Dispatchers.Main).launch`) is very dangerous in a Fragment. – Tenfour04 Sep 07 '22 at 12:41
  • @DarShan you mean always use viewLifecycleOwner.lifecycleScope.launch{} in fragments. Why is that so, and is there any rule like this in activities or I can just use normall CoroutineScope? – Kratos Sep 07 '22 at 12:42
  • 1
    Use regular `lifecycleScope` in an Activity. If you don't, your coroutine can outlive your Activity, or in the case of a Fragment your view's life, and then your coroutine is leaking your views or your whole activity. And in some cases you can cause a crash by trying to access the Context/Activity after it is already detached. – Tenfour04 Sep 07 '22 at 12:44
  • 1
    Always use lifecycle scoped coroutines, you do not want to leak flows, views & get crashes outside the scope of UI. Use `lifecycleScope.launch` in an `Activity` & `viewLifecycleOwner.lifecycleScope.launch` in a `Fragment`. – Darshan Sep 07 '22 at 12:44
  • Yes now I understand, great talk. Thank you guys – Kratos Sep 07 '22 at 12:54
  • @DarShan I tried now writing in fragments only lifecycleScope.launch like in activity without adding (viewLifecycleOwner.). And it looks it works the same. I think now we can conclude that for both activity and fragment, developers can use lifecycleScope.launch. (I write this for other people that might read it is surely helpfull) – Kratos Nov 23 '22 at 17:02
  • If you perform any UI based operation inside the coroutine then it is highly advised to use `viewLifecycleOwner.lifecycleScope` instead of `lifecycleScope`. The reason being that the Fragment may outlive the Fragment's View. See this for more info: https://stackoverflow.com/a/58663143/6819340 – Darshan Nov 24 '22 at 07:23

0 Answers0