Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SharedFlow that emits once (but buffers if there are no collectors) #3002

Open
matejdro opened this issue Oct 28, 2021 · 13 comments
Open

SharedFlow that emits once (but buffers if there are no collectors) #3002

matejdro opened this issue Oct 28, 2021 · 13 comments

Comments

@matejdro
Copy link

matejdro commented Oct 28, 2021

Is there a way to achieve a SharedFlow that will only emit once (replay = 0 behavior), BUT it would also buffer events until at least one collector is collecting them?

Use case for this would be sending one-off events to the UI (for example to display a one-off popup to the user). I want events to be ephemeral (if flow is collected again, they should not be replayed, so replay needs to stay at zero), but I also want events delivered in case nobody is collecting at the moment (maybe UI is in the background, so flows are not collected. But they would start getting collected as soon as UI comes into foreground)

From LiveData world, this would be similar to the SingleLiveEvent.

My current solution is to enable replay, but manually clear the replay cache after every item is emitted downstream:

private val _eventFlow = MutableSharedFlow<T>(replay = 999)
val eventFlow = _eventFlow.onEach { _eventFlow.resetReplayCache() }

This works, but I do not really like this solution, since it performs clearing on every item and it's probably not that efficient.

Another solution is using channels:

private val _eventChannel = Channel<T>(Channel.BUFFERED)
val eventFlow get() = _eventChannel.receiveAsFlow()

While above works, it only emits to one collector (if multiple collectors are awaiting for the UI events, only one will get the events), which is likely fine in the UI scenario I described above (only one screen is listening for events).

Is there a better way to achieve this that I am missing? Would it make sense to add parameter such as that to the MutableSharedFlow?

@psteiger
Copy link

What you can also do is waiting (suspending) until there is at least 1 collector before emitting to such flow.

I haven't put much thought about it, but beware race conditions. E.g. what if a subscription appears before the check and disappears before the emit?

suspend fun <T> MutableSharedFlow<T>.emitWhenSubscribedTo(value: T) {
    // fast path
    if (subscriptionCount.value > 0) {
        emit(value)
        return
    }
    // slow path
    subscriptionCount.first { it > 0 } // suspend until true
    emit(value)
}

@qwwdfsad qwwdfsad added the flow label Dec 7, 2021
@jemshit
Copy link

jemshit commented Jan 31, 2022

I need this too

@elizarov
Copy link
Contributor

The solution with the channel is how you are supposed to it.

@circusmagnus
Copy link

The solution with the channel is how you are supposed to it.

Channel will not work in case of multiple subscribers - only the first subscriber will receive an event.

In such a case - an event emitter, which is being subsribed by multiple Android Fragments / Composables / Activities - I use an event-wrapper construct.

Event wraper:

/** Event designed to be delivered only once to a concrete entity,
 * but it can also be delivered to multiple different entities.
 *
 * Keeps track of who has already handled its content.
 */

class OneTimeEvent<out T>(private val content: T) {

    private val handlers = CopyOnWriteArraySet<String>()

    /** @param asker Used to identify, whether this "asker" has already handled this Event.
     *
     * @return Event content or null if it has been already handled by asker
     */
    fun getIfNotHandled(asker: String): T? = if (handlers.add(asker)) content else null
    
}

Entities are identified by String. So that, if your fragment disappears after rotation and new fragment instance subcribes - it will identify itself by the same String id and will not receive already handled events again.

Such wrapped events can be emitted by ordinary SharedFlow with a non zero replay capacity - so SharedFlow will buffer events even if no one is listening to it.

It is helpful to use custom Flow operator to easily unwrap such OneTimeEvents:

fun <T> Flow<OneTimeEvent<T>>.filterNotHandledBy(consumerId: String): Flow<T> = transform { event ->
    event.getIfNotHandled(consumerId)?.let { emit(it) }
}

It will filter a Flow of OneTimeEvent emitting only non-handled events further down the stream and unpacking "real" events from the OneTimeEvent wrapper.


Still, if there is no need for multiple subscribers to such an event flow - it is much easier and problem-free to just use a Channel.

@zeeshanrasool91
Copy link

@circusmagnus can you share 1 usage example for your proposed solution

@circusmagnus
Copy link

circusmagnus commented Sep 7, 2022

Sure thing.
Interface to expose for clients

interface SharedEvents<out T> {

    fun getFor(consumerId: String): Flow<T>
}

Class into which one can push new events:

class EventQueue<T>(capacity: Int) : SharedEvents<T> {

    private val innerQueue = MutableSharedFlow<OneTimeEvent<T>>(replay = capacity)

    suspend fun push(event: T) {
        innerQueue.emit(OneTimeEvent(event))
    }

    override fun getFor(consumerId: String): Flow<T> = innerQueue.filterNotHandledBy(consumerId)
}

Usage on the event origin side:

        private val eventQueue = EventQueue<Event>(capacity = 64)
        val events: SharedEvents<Event>
           get() = eventQueue
    ...
   eventQueue.push(someEvent)

Usage on the client side (multiple subscribers allowed):

companion object {
     private const val TAG = "SomeFragment"
     }

 someViewModel.events
         .getFor(TAG) // TAG 
         .onEach { event -> event.handle() }
         .launchWhileStarted(lifecycle)

I have used it most commonly, when we have an android activity and a collection of fragments attached to it. One fragment allows the user to login (say, after 2fa auth is done and auth tokens are received) and both activity and other fragments should do something in response to being logged in - but they should react only once.

@Nek-12
Copy link

Nek-12 commented Dec 10, 2022

Looks like I have exactly this problem too, but the conversation seems to be progressing slowly. Is there any workaround for this, or has anyone found a solution? I see this issue has a lot of upvoters too

@danielesegato
Copy link

Hi everyone, I've written this gist with a SharedFlow that emits to multiple subscribers but buffer if there are no collectors at any given time. I called it ChannelSharedFlow, not the best name but it does what promises.

https://gist.github.com/danielesegato/160fabdcba5f563f1a171012377ea041

I'm not sure if this is what OP intended.
I kinda wish this was part of the kotlinx.coroutine library.

@circusmagnus
Copy link

circusmagnus commented Dec 13, 2022

I think, that it is difficult to incorporate such solution to public library, no matter, what you do, trying to emit events to multiple subscribers, which may disappear and reappear has some fundamental problems, which are unsolvable for all cases.

Say we have a 2 scenarios:
A. Android orientation change - several subscribing activities / fragments stop collecting and, after some small delay, new instances of them start collect again.
B. After user clicks a button, a completely new view appears on the screen and starts listening for shared events

Solution with EventWrapper (SharedFlow with non-zero replay buffer underneath):
Scenario A: new Instances of Act/Fragments will receive all events (each one will get all events), which were produced, while they were "absent". But only those, which were not handled already by them, when they were collecting before. Sounds good, works well
Scenario B: A completely new View may receive events, which were produced far back in time and are completely irrelevant now. But they were not obviously handled by this completely new View, so they need to be handled now. Not good. And how much of a buffer we should have? How much of a history should we replay? Hard to guess.

Solution with ChannelSharedFlow (SharedFlow with zero replay, but collecting from a Channel) :
Scenario A: First appearing instance of Activity/Fragment will cause a Channel to be drained of events (which appeared during "no -collector time") and published. However other Activities/Fragments are likely to appear just a few milliseconds later and they will not receive those events, which appeared during "no -collector time". That is not good, they will miss events, which they were meant to handle.
Scenario B: A completely new View will only receive new events (unless it is the first collector to appear) That should be ok. This View is new, it should not get those old events anyway.

So IMHO either solution works fine in some use cases, but not in all of them.

Check out Manuel Vivo article on One-Off event antipatterns: https://medium.com/androiddevelopers/viewmodel-one-off-event-antipatterns-16a1da869b95

I think he is right. One cannot guarentee only-once delivery, no-missed events and handle mutliple disappear-appear subscribers at the same time. Or at least not without timestamps. event versioning and such things, which are already handled by specialized solutions like Spark or Kafka

Either we may have events with one producer-one consumer implemented via a Channel with buffer. With all the Channel guarentees (and gotchas).

Or, if we want to handle multiple subscribers, which may disappear and reappear, then publishing a State (via StateFlow), rather than One-Off events is the solution. State, unlike Event, is always valid until it is replaced by newer State. So there is no problem with delivering it twice. Or delivering it too late.

@danielesegato
Copy link

Thanks for your answer @circusmagnus
It is indeed a tricky problem.

I believe scenario A and B are intrinsically separate. I cannot think of a scenario where a fragment recreating and a single Button would want to receive the same event flow.

In most cases I had the need to receive events rather than state it was to show errors or something that recently happened (ex. someone joining a session).

And for these cases it is important not to lose data while there's no subscription. But it is also important to have a zero-replay. You don't want to show an error shown minutes ago just because the user rotated the app.

Is this where clearReplayCache should be used? (Aka replay = 1 but after a few seconds of delivering clearing it?)

I think it would be nice if this was automatic. The scenario is common enough in my opinion to be part of the coroutine library.

The ChannelSharedFlow try to cover this use case. And of course it is very specific.

As you notice, it doesn't guarantee that all reattaching subscribers will get the event received while detached, only the first subscriber will. Which means it is probably not suited for multiple subscribers unless you accept this limitation.

There's somewhat something common to all these scenarios: the subscriber knows what it wants to receive rather than the producer. But I don't think there's a way to communicate it to the producer.

Would it be easier to keep data for a grace period in the replay cache during which it is considered "fresh" and replayed to all reattaching subscribers if the event is still fresh?

I'm not sure it seems like you'll never be able to find the perfect grace period duration.

I feel like my implementation cover a need and would be nice if it could remember which subscriber already received an item and avoid resending it while still providing it to another that didn't yet get it.

Would be even better if the SharedFlow could somehow distinguish between a returning subscription and a new one and decide if it should be replaying events based on that.

I wouldn't know how to implement such a SharedFlow to be honest.

bmarty added a commit to element-hq/element-android that referenced this issue Dec 16, 2022
bmarty added a commit to element-hq/element-android that referenced this issue Dec 16, 2022
bmarty added a commit to element-hq/element-android that referenced this issue Jan 6, 2023
hughns added a commit to hughns/element-android that referenced this issue Jan 6, 2023
commit a588989
Merge: 5606730 5ee3eef
Author: Benoit Marty <benoitm@matrix.org>
Date:   Fri Jan 6 18:45:18 2023 +0100

    Merge pull request element-hq#7875 from vector-im/feature/bma/releaseScript3

    Release script update

commit 5606730
Merge: baa4663 330a9be
Author: Benoit Marty <benoitm@matrix.org>
Date:   Fri Jan 6 18:44:55 2023 +0100

    Merge pull request element-hq#7905 from RiotTranslateBot/weblate-element-android-element-app

    Translations update from Weblate

commit baa4663
Merge: 93021a6 0d2fb8e
Author: Benoit Marty <benoitm@matrix.org>
Date:   Fri Jan 6 18:44:37 2023 +0100

    Merge pull request element-hq#7885 from vector-im/feature/bma/fixLint

    Fix lint false positive

commit 93021a6
Merge: f856142 e9d1de8
Author: Benoit Marty <benoitm@matrix.org>
Date:   Fri Jan 6 18:43:53 2023 +0100

    Merge pull request element-hq#7724 from vector-im/feature/bma/launchWhenResumed

    Observe ViewEvents only when resumed

commit e9d1de8
Author: Benoit Marty <benoit@matrix.org>
Date:   Fri Jan 6 17:36:40 2023 +0100

    Fix compilation issue after rebase.

commit 330a9be
Merge: f856142 4f2550a
Author: Weblate <noreply@weblate.org>
Date:   Fri Jan 6 16:33:47 2023 +0000

    Merge branch 'origin/develop' into Weblate.

commit 4f2550a
Author: Linerly <linerly@protonmail.com>
Date:   Wed Jan 4 22:47:24 2023 +0000

    Translated using Weblate (Indonesian)

    Currently translated at 100.0% (89 of 89 strings)

    Translation: Element Android/Element Android Store
    Translate-URL: https://translate.element.io/projects/element-android/element-store/id/

commit 5734a27
Author: waclaw66 <waclaw66@seznam.cz>
Date:   Wed Jan 4 16:04:26 2023 +0000

    Translated using Weblate (Czech)

    Currently translated at 100.0% (89 of 89 strings)

    Translation: Element Android/Element Android Store
    Translate-URL: https://translate.element.io/projects/element-android/element-store/cs/

commit 0882e1b
Author: Jeff Huang <s8321414@gmail.com>
Date:   Thu Jan 5 02:10:13 2023 +0000

    Translated using Weblate (Chinese (Traditional))

    Currently translated at 100.0% (89 of 89 strings)

    Translation: Element Android/Element Android Store
    Translate-URL: https://translate.element.io/projects/element-android/element-store/zh_Hant/

commit 53db988
Author: Christian Paul <info@jaller.de>
Date:   Thu Jan 5 16:06:48 2023 +0000

    Translated using Weblate (Esperanto)

    Currently translated at 2.2% (2 of 89 strings)

    Translation: Element Android/Element Android Store
    Translate-URL: https://translate.element.io/projects/element-android/element-store/eo/

commit ff9cf8f
Author: Danial Behzadi <dani.behzi@ubuntu.com>
Date:   Wed Jan 4 17:43:34 2023 +0000

    Translated using Weblate (Persian)

    Currently translated at 100.0% (89 of 89 strings)

    Translation: Element Android/Element Android Store
    Translate-URL: https://translate.element.io/projects/element-android/element-store/fa/

commit 8a5aad1
Author: Priit Jõerüüt <riot@joeruut.com>
Date:   Thu Jan 5 07:22:25 2023 +0000

    Translated using Weblate (Estonian)

    Currently translated at 100.0% (89 of 89 strings)

    Translation: Element Android/Element Android Store
    Translate-URL: https://translate.element.io/projects/element-android/element-store/et/

commit 2903a64
Author: Ihor Hordiichuk <igor_ck@outlook.com>
Date:   Wed Jan 4 19:24:53 2023 +0000

    Translated using Weblate (Ukrainian)

    Currently translated at 100.0% (89 of 89 strings)

    Translation: Element Android/Element Android Store
    Translate-URL: https://translate.element.io/projects/element-android/element-store/uk/

commit 96363fb
Author: Jozef Gaal <preklady@mayday.sk>
Date:   Wed Jan 4 16:18:18 2023 +0000

    Translated using Weblate (Slovak)

    Currently translated at 100.0% (89 of 89 strings)

    Translation: Element Android/Element Android Store
    Translate-URL: https://translate.element.io/projects/element-android/element-store/sk/

commit 271b828
Author: Szimszon <github@oregpreshaz.eu>
Date:   Wed Jan 4 18:55:35 2023 +0000

    Translated using Weblate (Hungarian)

    Currently translated at 100.0% (89 of 89 strings)

    Translation: Element Android/Element Android Store
    Translate-URL: https://translate.element.io/projects/element-android/element-store/hu/

commit bd21f03
Author: Glandos <bugs-github@antipoul.fr>
Date:   Thu Jan 5 08:42:07 2023 +0000

    Translated using Weblate (French)

    Currently translated at 100.0% (89 of 89 strings)

    Translation: Element Android/Element Android Store
    Translate-URL: https://translate.element.io/projects/element-android/element-store/fr/

commit 860df01
Author: Vri <element@vrifox.cc>
Date:   Wed Jan 4 16:20:15 2023 +0000

    Translated using Weblate (German)

    Currently translated at 100.0% (89 of 89 strings)

    Translation: Element Android/Element Android Store
    Translate-URL: https://translate.element.io/projects/element-android/element-store/de/

commit ed84212
Author: Besnik Bleta <besnik@programeshqip.org>
Date:   Wed Jan 4 17:01:03 2023 +0000

    Translated using Weblate (Albanian)

    Currently translated at 99.3% (2558 of 2576 strings)

    Translation: Element Android/Element Android App
    Translate-URL: https://translate.element.io/projects/element-android/element-app/sq/

commit f790921
Author: Mateus Rodrigues Costa <mateusrodcosta@gmail.com>
Date:   Wed Jan 4 21:12:32 2023 +0000

    Translated using Weblate (Portuguese (Brazil))

    Currently translated at 100.0% (2576 of 2576 strings)

    Translation: Element Android/Element Android App
    Translate-URL: https://translate.element.io/projects/element-android/element-app/pt_BR/

commit 3098ec1
Author: overtinkering <overtinker@yandex.com>
Date:   Thu Jan 5 18:02:33 2023 +0000

    Translated using Weblate (Spanish)

    Currently translated at 90.7% (2338 of 2576 strings)

    Translation: Element Android/Element Android App
    Translate-URL: https://translate.element.io/projects/element-android/element-app/es/

commit 725722d
Author: Christian Paul <info@jaller.de>
Date:   Thu Jan 5 16:14:10 2023 +0000

    Translated using Weblate (Esperanto)

    Currently translated at 76.0% (1960 of 2576 strings)

    Translation: Element Android/Element Android App
    Translate-URL: https://translate.element.io/projects/element-android/element-app/eo/

commit ea92464
Author: Christian Paul <info@jaller.de>
Date:   Thu Jan 5 16:51:43 2023 +0000

    Translated using Weblate (Danish)

    Currently translated at 10.2% (264 of 2576 strings)

    Translation: Element Android/Element Android App
    Translate-URL: https://translate.element.io/projects/element-android/element-app/da/

commit f856142
Merge: b7076a1 85cfa43
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Jan 6 16:07:44 2023 +0100

    Merge pull request element-hq#7886 from vector-im/feature/mna/past-polls-ui

    [Poll] Render past polls list of a room (PSG-1029)

commit b7076a1
Merge: 41bcdd7 dbf3b76
Author: Benoit Marty <benoitm@matrix.org>
Date:   Fri Jan 6 15:16:16 2023 +0100

    Merge pull request element-hq#7879 from vector-im/feature/bma/still_investigating

    Reduce number of crypto database transactions when handling the sync response

commit 7b1724f
Author: Benoit Marty <benoit@matrix.org>
Date:   Fri Jan 6 15:13:01 2023 +0100

    changelog

commit 9768430
Author: Benoit Marty <benoit@matrix.org>
Date:   Mon Dec 19 18:32:07 2022 +0100

    Fix test compilation issue

commit 71bd4f4
Author: Benoit Marty <benoit@matrix.org>
Date:   Wed Dec 7 17:48:25 2022 +0100

    Ensure posted events from the ViewModel are consumed (once) by the UI
    Inspired from Kotlin/kotlinx.coroutines#3002

commit 9c79d23
Author: Benoit Marty <benoitm@matrix.org>
Date:   Fri Dec 16 21:02:33 2022 +0100

    Ensure event are not sent if the lifecycle state is not RESUMED

commit 0dd1abb
Author: Benoit Marty <benoit@matrix.org>
Date:   Tue Dec 6 13:02:02 2022 +0100

    Rename method

commit 41bcdd7
Merge: b8da53b 7fc9705
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Jan 6 14:18:20 2023 +0100

    Merge pull request element-hq#7867 from vector-im/feature/mna/active-polls-ui

    [Poll] Render active polls list of a room (PSG-908)

commit 85cfa43
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Jan 6 14:13:58 2023 +0100

    Using ordinal of enum to render tabs

commit b8da53b
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Fri Jan 6 11:56:11 2023 +0000

    Bump checker from 3.27.0 to 3.29.0 (element-hq#7903)

    Bumps [checker](https://github.com/typetools/checker-framework) from 3.27.0 to 3.29.0.
    - [Release notes](https://github.com/typetools/checker-framework/releases)
    - [Changelog](https://github.com/typetools/checker-framework/blob/master/docs/CHANGELOG.md)
    - [Commits](typetools/checker-framework@checker-framework-3.27.0...checker-framework-3.29.0)

    ---
    updated-dependencies:
    - dependency-name: org.checkerframework:checker
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...

    Signed-off-by: dependabot[bot] <support@github.com>

    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

commit e88e874
Merge: 2e95d4f c3ad7fa
Author: Benoit Marty <benoitm@matrix.org>
Date:   Fri Jan 6 10:35:14 2023 +0100

    Merge pull request element-hq#7865 from vector-im/dependabot/gradle/org.owasp-dependency-check-gradle-7.4.3

    Bump dependency-check-gradle from 7.4.1 to 7.4.3

commit 2e95d4f
Merge: f1bd9b2 87e661e
Author: Florian Renaud <Florian14@users.noreply.github.com>
Date:   Fri Jan 6 09:10:00 2023 +0100

    Merge pull request element-hq#7899 from vector-im/bugfix/fre/buffering_on_last_chunk

    [Voice Broadcast] Stop listening if we reach the last received chunk and there is no last sequence number

commit 9b5fda2
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Thu Jan 5 15:45:35 2023 +0100

    Fix after rebase

commit a5d076a
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Wed Jan 4 10:49:07 2023 +0100

    Adding total votes status for ended poll items

commit 05363dc
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Wed Jan 4 10:30:57 2023 +0100

    Adding winner option views for ended poll items

commit 1cc2644
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Wed Jan 4 10:12:34 2023 +0100

    Renaming some ui fields

commit 3deae11
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Tue Jan 3 17:32:41 2023 +0100

    Adding extra data for ended poll

commit cf82486
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 17:38:55 2022 +0100

    Adding mocked data for ended polls

commit 740591c
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 17:31:23 2022 +0100

    Updating unit tests

commit cb45056
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 17:28:57 2022 +0100

    Mutualizing list fragments and add ended polls tab

commit 0b53591
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 15:50:32 2022 +0100

    Adding changelog entry

commit 7fc9705
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Thu Jan 5 16:37:06 2023 +0100

    Adding importantForAccessibility attribute to icon

commit 2dab6ed
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Thu Jan 5 15:27:11 2023 +0100

    Fix horizontal margin of tabs

commit ff9e78b
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Thu Jan 5 15:20:20 2023 +0100

    Use classical for loop instead of forEach

commit d604035
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Thu Jan 5 15:09:41 2023 +0100

    Renaming of filter enum

commit 87e661e
Author: Florian Renaud <florianr@element.io>
Date:   Thu Jan 5 14:36:22 2023 +0100

    Add changelog file

commit 0d2fb8e
Author: Benoit Marty <benoit@matrix.org>
Date:   Wed Jan 4 10:17:35 2023 +0100

    Lint: fix KotlinNullnessAnnotation warning

commit dbf3b76
Author: Benoit Marty <benoitm@matrix.org>
Date:   Thu Jan 5 11:54:19 2023 +0100

    Update doc.

commit 27d3218
Author: Benoit Marty <benoit@matrix.org>
Date:   Thu Jan 5 11:04:20 2023 +0100

    Aggregate data outside of the RealmCryptoStore.

commit 682bb8b
Author: Florian Renaud <florianr@element.io>
Date:   Wed Jan 4 14:06:58 2023 +0100

    VB - Stop listening if we reach the last received chunk and there is no last sequence number

commit 30940cb
Author: Benoit Marty <benoit@matrix.org>
Date:   Thu Jan 5 09:53:12 2023 +0100

    Rename `UserCrossSigningKeys` to `UserIdentity`

commit 7e26c4b
Author: Benoit Marty <benoit@matrix.org>
Date:   Thu Jan 5 09:48:25 2023 +0100

    Rename fun

commit 354554e
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 16:45:28 2022 +0100

    Ignore missing ContentDescription

commit e82c7af
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 15:48:14 2022 +0100

    Replace usage of colorAccent

commit 6c0c5e5
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 15:12:12 2022 +0100

    Rename poll item layout to be more generic

commit bd9c53a
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 14:57:37 2022 +0100

    Show message when list is empty

commit e0b7793
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 14:27:11 2022 +0100

    Changing the date format

commit bc985aa
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 14:19:50 2022 +0100

    Adding unit tests for ViewModel

commit 71b7edc
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 12:12:57 2022 +0100

    Adding debug log

commit bf67d25
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 12:08:55 2022 +0100

    Allow access of poll history only in debug variant

commit 8de86e7
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 11:59:48 2022 +0100

    Render mocked data get from use case

commit 77d3b7d
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 11:40:41 2022 +0100

    Fix missing id in Epoxy model

commit f20513e
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 10:56:44 2022 +0100

    Render the active polls list on fragment

commit 7b63f89
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 10:42:42 2022 +0100

    Epoxy controller to render active poll list

commit 9f97579
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Fri Dec 30 10:07:50 2022 +0100

    Epoxy model for active poll

commit 10133bd
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Thu Dec 29 17:46:07 2022 +0100

    Setup tab layout when landing on the room polls screen

commit 7436c2e
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Thu Dec 29 16:41:42 2022 +0100

    Navigate to new empty screen

commit cba960f
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Thu Dec 29 16:05:52 2022 +0100

    Adding new entry "Poll history" into room profile screen

commit e903dac
Author: Maxime NATUREL <46314705+mnaturel@users.noreply.github.com>
Date:   Thu Dec 29 15:40:59 2022 +0100

    Adding changelog entry

commit 437b93c
Author: Benoit Marty <benoitm@matrix.org>
Date:   Wed Jan 4 11:35:04 2023 +0100

    Add some doc

commit 06f3c11
Author: Benoit Marty <benoit@matrix.org>
Date:   Tue Jan 3 16:43:09 2023 +0100

    Changelog

commit 02e7157
Author: Benoit Marty <benoitm@matrix.org>
Date:   Tue Jan 3 16:16:17 2023 +0100

    Introduce CryptoCrossSigningKeys container

commit 4c4ef0d
Author: Benoit Marty <benoitm@matrix.org>
Date:   Tue Jan 3 15:57:39 2023 +0100

    Batch insertion of  user data after downloading keys.

commit f26178f
Author: Benoit Marty <benoitm@matrix.org>
Date:   Tue Jan 3 15:21:03 2023 +0100

    Avoid useless transaction

commit a386a47
Author: Benoit Marty <benoitm@matrix.org>
Date:   Tue Jan 3 15:18:32 2023 +0100

    Crypto store: Log realm transactions and the duration

commit c1a8bf8
Author: Benoit Marty <benoitm@matrix.org>
Date:   Tue Jan 3 15:15:15 2023 +0100

    Batch insertion of  `shouldEncryptForInvitedMembers`

commit 6f384c7
Author: Benoit Marty <benoitm@matrix.org>
Date:   Tue Jan 3 15:02:45 2023 +0100

    Batch insertion of  `shouldShareHistory`

commit 0e504e9
Author: Benoit Marty <benoitm@matrix.org>
Date:   Tue Jan 3 11:55:41 2023 +0100

    Format

commit 8375901
Author: Benoit Marty <benoitm@matrix.org>
Date:   Tue Jan 3 11:55:32 2023 +0100

    Avoid launching coroutine for nothing.

commit 56986c3
Author: Benoit Marty <benoit@matrix.org>
Date:   Mon Jan 2 21:15:08 2023 +0100

    Add a way to get the access token from the advances settings.

commit 5ee3eef
Author: Benoit Marty <benoit@matrix.org>
Date:   Mon Jan 2 16:55:25 2023 +0100

    Pull branch sooner to ensure release version is correctly guessed

commit c3ad7fa
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Thu Dec 29 23:02:43 2022 +0000

    Bump dependency-check-gradle from 7.4.1 to 7.4.3

    Bumps dependency-check-gradle from 7.4.1 to 7.4.3.

    ---
    updated-dependencies:
    - dependency-name: org.owasp:dependency-check-gradle
      dependency-type: direct:production
      update-type: version-update:semver-patch
    ...

    Signed-off-by: dependabot[bot] <support@github.com>

commit b3d578d
Author: Benoit Marty <benoit@matrix.org>
Date:   Thu Dec 15 12:44:40 2022 +0100

    Release script: Improve creation of the release on GitHub.

commit 5e1d3e6
Author: Benoit Marty <benoitm@matrix.org>
Date:   Thu Dec 15 12:09:27 2022 +0100

    Escape %
@mo0rti
Copy link

mo0rti commented Mar 30, 2023

I had a problem like this with ShareFlow. The workaround was by adding a delay(1)
Update: adding yield() works for me. Thanks to @pablichjenkov

suspend fun mainSharedFlow(
    coroutineScope: CoroutineScope
) {
    val dataFlow = MutableSharedFlow<Int>()

    // First consumer
    coroutineScope.launch {
        dataFlow.collect {
            println("Consumer 1: $it")
        }
    }

    // Second consumer
    coroutineScope.launch {
        dataFlow.collect {
            println("Consumer 2: $it")
        }
    }

    yield()  // Added this to fix the issue

    // Emit data
    dataFlow.emit(1)
    dataFlow.emit(2)
    dataFlow.emit(3)
}

and code in

override fun onCreate(savedInstanceState: Bundle?) {

        // ....

        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                mainSharedFlow(this)
            }
        }
}

@pablichjenkov
Copy link

Instead of using delay you can give it a try calling yield

@dkhalanskyjb
Copy link
Collaborator

Note that the workaround will only work reliably for single-threaded dispatchers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests