What happen with LiveData after delay

Viewed 282

Here is my code :

HomeFragment

...

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)

    homeViewModel.myTest.observe(viewLifecycleOwner) {
        Log.d(TAG, "myTest=$it")
    }

    lifecycleScope.launch {
        homeViewModel.doSomethingForMyTest()
    }

}
...

HomeViewModel

...

private val _myTest = MutableLiveData<String>()
val myTest: LiveData<String> = _myTest

fun doSomethingForMyTest() {
    Log.i(TAG, "doSomethingForMyTest start: ${System.currentTimeMillis()}")
    (1..3).forEach {
        _myTest.value = it.toString()
    }
    Log.i(TAG, "doSomethingForMyTest end: ${System.currentTimeMillis()}")
}

...

log :

I/HomeViewModel: doSomethingForMyTest start: 1628586904976
I/HomeViewModel: doSomethingForMyTest end: 1628586904977
D/HomeFragment: myTest=3

If add delay before I call the function, like this :

HomeFragment

...

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    homeViewModel.myTest.observe(viewLifecycleOwner) {
        Log.d(TAG, "myTest=$it")
    }
    lifecycleScope.launch {
        delay(1)
        homeViewModel.doSomethingForMyTest()
    }
}

...

log :

I/HomeViewModel: doSomethingForMyTest start: 1628587129413
D/HomeFragment: myTest=1
D/HomeFragment: myTest=2
D/HomeFragment: myTest=3
I/HomeViewModel: doSomethingForMyTest end: 1628587129414

As you can see, I don’t know the difference...

Why logs different?

1 Answers

There are two things you're missing:

viewLifecycleOwner - during onViewCreated it's still in the INITIALIZED state so your liveData observer will not receive updates until fragment is moved to STARTED state.

lifecycleScope - it is backed by Dispatchers.Main.immediate which means launch is executed immediately when you're already in the right context (ui thread) until first suspending call.

In first case you add observer then your three updates run immediately but observer is not active yet so it only receives the last value when fragments viewLifecycleOwner moves to STARTED state.

In second case delay is a suspending point so your launch cannot execute in-line. Since lifecycleScope is backed by Dispatchers.Main call has to be delayed until next ui-thread cycle during which fragment is already in STARTED state so your observer is active and it receives each update in real time.

Related