<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/one-badge-three-deliveries-how-android-flutter-and-compose-keep-your-ui-in-sync-fph6mmdcv" -->

---
title: One Badge, Three Deliveries: How Android, Flutter, and...
description: A comparison of state management across Android Views (LiveData), Flutter (Dart streams), and Jetpack Compose/KMP (StateFlow), using a cart badge as the...
canonical: https://daily.dev/posts/one-badge-three-deliveries-how-android-flutter-and-compose-keep-your-ui-in-sync-fph6mmdcv
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: One Badge, Three Deliveries: How Android, Flutter, and Compose Keep Your UI in Sync | daily.dev
og:description: A comparison of state management across Android Views (LiveData), Flutter (Dart streams), and Jetpack Compose/KMP (StateFlow), using a cart badge as the...
og:url: https://daily.dev/posts/one-badge-three-deliveries-how-android-flutter-and-compose-keep-your-ui-in-sync-fph6mmdcv
og:image: https://api.daily.dev/og/posts/FpH6mMDCV.png
og:image:alt: One Badge, Three Deliveries: How Android, Flutter, and Compose Keep Your UI in Sync
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# One Badge, Three Deliveries: How Android, Flutter, and Compose Keep Your UI in Sync

**[Medium](https://daily.dev/sources/medium_js)** · 8 min read · 0 upvotes · 0 comments

## Summary

A comparison of state management across Android Views (LiveData), Flutter (Dart streams), and Jetpack Compose/KMP (StateFlow), using a cart badge as the concrete example. The post frames the problem around three delivery questions: whether subscriptions survive while a screen is covered, whether late subscribers receive the current value, and who handles cleanup. LiveData acts as a lifecycle-aware receptionist that pauses and replays; Flutter's broadcast streams are loudspeakers with no built-in replay, requiring manual discipline via BehaviorSubject or Bloc; StateFlow makes the current value always available by type contract, with structured concurrency handling cancellation. Each approach prevents different failure modes but carries its own hidden costs.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://medium.com/@angelinaballerina/one-badge-three-deliveries-how-android-flutter-and-compose-keep-your-ui-in-sync-2ef1e84a6038>

## Questions this post answers

### Why does my Flutter badge show a stale count when I navigate to a screen after the cart already changed elsewhere?

A plain Dart broadcast stream does not replay past events to late subscribers, so if the change happened before the widget subscribed, it sees nothing until the next update. Fix this by seeding the UI with a current value using rxdart's BehaviorSubject, Bloc's synchronously-read state, initialData or startWith parameters, or by re-fetching on return via RouteObserver.

_Comparing Flutter state approaches before you build your own replay logic is easier with daily.dev around._

### How does StateFlow guarantee that new collectors always get the current value in Kotlin?

StateFlow always holds a value accessible via .value, so every new collector receives the latest state immediately upon subscribing, eliminating the blank-badge problem that can occur with cold streams or non-replaying observables. This is combined with collectAsStateWithLifecycle, which pauses collection while a screen is invisible and resumes with the current value when it returns.

_Developers weighing StateFlow against Flutter streams can track these tradeoffs on daily.dev._

### What does LiveData's observe() function require and why does it need a lifecycle owner?

LiveData's observe() method requires a LifecycleOwner argument, meaning a subscription cannot be created without giving the framework a way to automatically cancel it later. This lifecycle-awareness pauses delivery while a screen is covered, replays the latest value when it becomes visible again, and removes the subscription when the screen is destroyed, preventing crashes from updates hitting dead views.

_Android engineers debugging lifecycle-related state bugs can follow deeper comparisons like this on daily.dev._

## Similar posts on daily.dev

- [One Tap, Three Machines: How Android Views, Flutter, and Compose Actually Render Your UI](https://daily.dev/posts/one-tap-three-machines-how-android-views-flutter-and-compose-actually-render-your-ui-ruoe8zjtc) · ProAndroidDev · 0 upvotes · 0 comments
- [AppState in Jetpack Compose: The Missing Piece for Building Large-Scale Android Apps](https://daily.dev/posts/appstate-in-jetpack-compose-the-missing-piece-for-building-large-scale-android-apps-gsrhvyqeq) · Medium · 2 upvotes · 1 comments
- [Android Architecture Is Quietly Moving Beyond ViewModel as a State Holder](https://daily.dev/posts/android-architecture-is-quietly-moving-beyond-viewmodel-as-a-state-holder-0e2pkua20) · ProAndroidDev · 12 upvotes · 0 comments
- [Process Death and SavedStateHandle in Android](https://daily.dev/posts/process-death-and-savedstatehandle-in-android-82qtjktll) · Atomic Spin · 0 upvotes · 0 comments
- [Kotlin Flows in Android: A Clear Mental Model](https://daily.dev/posts/kotlin-flows-in-android-a-clear-mental-model-ln8rffwwm) · Medium · 0 upvotes · 0 comments

---

Tags: [#android](https://daily.dev/tags/android), [#flutter](https://daily.dev/tags/flutter), [#kotlin](https://daily.dev/tags/kotlin), [#jetpack-compose](https://daily.dev/tags/jetpack-compose)

[View this post on daily.dev](https://daily.dev/posts/one-badge-three-deliveries-how-android-flutter-and-compose-keep-your-ui-in-sync-fph6mmdcv)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"One Badge, Three Deliveries: How Android, Flutter, and Compose Keep Your UI in Sync","url":"https://daily.dev/posts/one-badge-three-deliveries-how-android-flutter-and-compose-keep-your-ui-in-sync-fph6mmdcv","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/one-badge-three-deliveries-how-android-flutter-and-compose-keep-your-ui-in-sync-fph6mmdcv"},"datePublished":"2026-07-20T20:07:33.229Z","dateModified":"2026-09-14T08:16:01.981Z","description":"A comparison of state management across Android Views (LiveData), Flutter (Dart streams), and Jetpack Compose/KMP (StateFlow), using a cart badge as the...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/43890f8e84ea8896a6ece5163cc1bb9e?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/43890f8e84ea8896a6ece5163cc1bb9e?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"Medium","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"Medium","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1/logos/medium","url":"https://daily.dev/sources/medium_js"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/one-badge-three-deliveries-how-android-flutter-and-compose-keep-your-ui-in-sync-fph6mmdcv","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"android,flutter,kotlin,jetpack-compose","timeRequired":"PT8M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"Medium","item":"https://daily.dev/sources/medium_js"},{"@type":"ListItem","position":3,"name":"One Badge, Three Deliveries: How Android, Flutter, and Compose Keep Your UI in Sync"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/one-badge-three-deliveries-how-android-flutter-and-compose-keep-your-ui-in-sync-fph6mmdcv#faq","mainEntity":[{"@type":"Question","name":"Why does my Flutter badge show a stale count when I navigate to a screen after the cart already changed elsewhere?","acceptedAnswer":{"@type":"Answer","text":"A plain Dart broadcast stream does not replay past events to late subscribers, so if the change happened before the widget subscribed, it sees nothing until the next update. Fix this by seeding the UI with a current value using rxdart's BehaviorSubject, Bloc's synchronously-read state, initialData or startWith parameters, or by re-fetching on return via RouteObserver. Comparing Flutter state approaches before you build your own replay logic is easier with daily.dev around."}},{"@type":"Question","name":"How does StateFlow guarantee that new collectors always get the current value in Kotlin?","acceptedAnswer":{"@type":"Answer","text":"StateFlow always holds a value accessible via .value, so every new collector receives the latest state immediately upon subscribing, eliminating the blank-badge problem that can occur with cold streams or non-replaying observables. This is combined with collectAsStateWithLifecycle, which pauses collection while a screen is invisible and resumes with the current value when it returns. Developers weighing StateFlow against Flutter streams can track these tradeoffs on daily.dev."}},{"@type":"Question","name":"What does LiveData's observe() function require and why does it need a lifecycle owner?","acceptedAnswer":{"@type":"Answer","text":"LiveData's observe() method requires a LifecycleOwner argument, meaning a subscription cannot be created without giving the framework a way to automatically cancel it later. This lifecycle-awareness pauses delivery while a screen is covered, replays the latest value when it becomes visible again, and removes the subscription when the screen is destroyed, preventing crashes from updates hitting dead views. Android engineers debugging lifecycle-related state bugs can follow deeper comparisons like this on daily.dev."}}]}
```

