What is the difference between emit and tryEmit on a MutableSharedFlow, and when can tryEmit return false?
answer
- emit = suspend, back-pressures
- tryEmit = non-suspend, returns Boolean
- false ONLY when full + SUSPEND
- DROP_* => tryEmit always true
- tryEmit for synchronous callbacks
basics
~10 semit is a suspend function that waits if the buffer is full. tryEmit is non-suspending and returns true/false: it returns false when it would have to suspend to deliver the value.
solid answer
~40 semit is a suspend function: if the buffer is full and onBufferOverflow is SUSPEND, it suspends the calling coroutine until there is room (back-pressure). tryEmit is its non-suspending counterpart, callable from non-coroutine code; it attempts to add the value immediately and returns a Boolean. tryEmit returns false only when adding the value would require suspending — i.e. the buffer is full and overflow strategy is SUSPEND. With DROP_OLDEST or DROP_LATEST the buffer can always make room (or drop the incoming value), so tryEmit always returns true. With replay+extraBufferCapacity > 0 and a non-suspending overflow policy, tryEmit also generally succeeds. Use emit from a coroutine when you want guaranteed delivery with back-pressure; use tryEmit from synchronous callbacks (e.g. listeners) where you can't suspend, accepting that it may drop under SUSPEND policy.
go deeper
Knows emit suspends and tryEmit returns a Boolean without suspending.
Pinpoints that tryEmit returns false only when buffer is full under SUSPEND, and chooses emit vs tryEmit by context.
Explains the back-pressure semantics, the DROP-policy implication that tryEmit always succeeds, and treats a false result as a real loss to handle.
Designs emission strategy across suspend/non-suspend producers, choosing capacity and overflow so callbacks never silently drop critical events.
## emit (suspending) ```kotlin suspend fun emit(value: T) ``` `emit` adds the value to the shared buffer and delivers it to subscribers. If the buffer is full **and** `onBufferOverflow == SUSPEND`, `emit` **suspends** the caller until a slot frees up. This is the back-pressure mechanism. Because it can suspend, it must be called from a coroutine / suspend context. ## tryEmit (non-suspending) ```kotlin fun tryEmit(value: T): Boolean ``` `tryEmit` is the synchronous alternative — usable from non-suspend code such as a Java listener, click handler, or callback. It never suspends. It returns: - **true** — the value was buffered/delivered (or made room via DROP_OLDEST, or was itself dropped via DROP_LATEST — both count as "handled"). - **false** — it would have had to suspend to add the value, i.e. the buffer is full and the policy is SUSPEND. ## When tryEmit returns false Exactly one situation: **buffer full + onBufferOverflow == SUSPEND**. In every other configuration (DROP_OLDEST, DROP_LATEST, or free buffer space) it returns true. ```kotlin val events = MutableSharedFlow<Int>(extraBufferCapacity = 1) // From a non-suspend callback: button.setOnClickListener { val accepted = events.tryEmit(clicks++) if (!accepted) Log.w("bus", "event dropped") } ``` ## Guidance - Inside a coroutine where dropping is unacceptable: use `emit` (it back-pressures). - From synchronous code where you cannot suspend: use `tryEmit`, and either size `extraBufferCapacity` adequately or pick DROP_OLDEST so it never returns false. - Never ignore a `false` result silently — it means a lost emission. - Note: on `StateFlow` (a SharedFlow), `tryEmit` always succeeds because it only conflates the latest value.
- Can you call tryEmit and then assume the value reached all subscribers?No. true means it was accepted into the buffer; slow subscribers still consume asynchronously, and under DROP policies older values may have been evicted.
- Why does tryEmit on a StateFlow always return true?StateFlow conflates to a single latest value with no real buffer to overflow, so setting the value always succeeds.
saying these in an interview costs you the question
- Saying tryEmit returns false whenever there are no subscribers
- Claiming emit never suspends
- Using tryEmit and ignoring the Boolean result
- Thinking tryEmit guarantees synchronous delivery to all collectors