question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

StateFlow .combine usage with .asLiveData

See original GitHub issue

I’m using StateFlow under the hood, but still exposing LiveData in my API. I’m currently experiencing some unexpected behavior with regard to calling combine to join two instances of MutableStateFlow, and subsequently using the combined value as LiveData.

    private val _read = MutableStateFlow<ChannelUserRead?>(null)
    private val _messages = MutableStateFlow<Map<String, Message>>(emptyMap())

    ...

    private val _unreadCount: StateFlow<Int?> =
        _read.combine(_messages) { channelUserRead: ChannelUserRead?, messagesMap: Map<String, Message> ->
            computeUnreadCount(domainImpl.currentUser, channelUserRead, messagesMap.values.toList())
        }.stateIn(domainImpl.scope, SharingStarted.Eagerly, 0)

    override val unreadCount: LiveData<Int?> = _unreadCount.asLiveData()

I would expect this to run the combine transformation any time _read or _messages value changes, and also notify any observers of the unreadCount. This seems to work in the acutal app, but previously passing tests now fail when trying to validate unreadCount.value. It seems that, when under test, the combine transformation is called once on instantiation, and not when _messages.value is updated, and so

            channelController.unreadCount.getOrAwaitValue().let { unreadCount ->
                Truth.assertThat(unreadCount).isEqualTo(1)
            }

always fails with actual being 0.

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:1
  • Comments:8 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
elizarovcommented, Dec 3, 2020

It is not expected, but it may, indeed, change the behavior, just like putting delay makes it work in this particular test case. This is definitely not a general solution and does not guarantee anything if you write a longer test. Data propagation through a flow is, in general, asynchronous. On the other hand, putting advanceUntilIdle() after updates guarantees that all data propagation had finished and you can safely assert the derived values.

0reactions
zsmb13commented, Dec 3, 2020

Makes sense, thanks for the explanations! I think we can close this 😄

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to combine livedata and kotlin flow - Stack Overflow
You can combine both streams of data into one stream and use their results. For example we can convert LiveData to Flow ,...
Read more >
Using StateFlow over LiveData for end-to-end operations
I'll demonstrate their use in a small sample app that leverages StateFlow for two use cases. First, we'll see how it provides the...
Read more >
StateFlow and SharedFlow - Android Developers
StateFlow and SharedFlow are Flow APIs that enable flows to optimally emit state updates and emit values to multiple consumers.
Read more >
Kotlin's Flow in ViewModels: it's complicated - Christophe Beyls
Using StateFlow as trigger in a ViewModel. A common scenario is to use a trigger-based approach to load data in a ViewModel: every...
Read more >
Developers - StateFlow .combine usage with .asLiveData -
StateFlow .combine usage with .asLiveData. Kotlin. 25 November 2020 Posted by carterhudson. I'm using StateFlow under the hood, but still exposing LiveData ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found