MyFamilyTracker
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
LiveData is deprecated. StateFlow is the answer — but knowing why matters more than knowing which. Here's the practical breakdown after switching 22+ Android apps.
On this page
LiveData is effectively deprecated. Google hasn't removed it, but they've stopped recommending it for new development. If you're still using it in 2026, here's everything you need to know to switch — and why it matters beyond just following trends.
LiveData is a lifecycle-aware observable data holder built for Android Views. It was designed before Kotlin Coroutines existed and before Jetpack Compose was a thing. It solves the problem of updating UI safely across lifecycle states using Android's Lifecycle system.
It works. It's not broken. But it was designed for a world that no longer exists.
StateFlow is a Kotlin Coroutines construct — a hot Flow that always has a value, emits to collectors, and is lifecycle-independent. It doesn't know or care about Android. That's the point.
// LiveData
private val _uiState = MutableLiveData<LoginUiState>()
val uiState: LiveData<LoginUiState> = _uiState
// StateFlow
private val _uiState = MutableStateFlow<LoginUiState>(LoginUiState.Idle)
val uiState: StateFlow<LoginUiState> = _uiState.asStateFlow()Structurally similar. Behaviorally very different.
Initial value. StateFlow always requires an initial value. LiveData doesn't. This sounds minor but it eliminates an entire class of null-handling bugs — your UI always has something to render.
Lifecycle awareness. LiveData handles this automatically. StateFlow doesn't — you collect it using
repeatOnLifecyclecollectAsStateWithLifecycleCoroutine integration. LiveData has
liveData {}switchMapmapfiltercombineflatMapLatestTestability. Testing StateFlow is cleaner. You don't need
InstantTaskExecutorRuleCompose compatibility.
collectAsStateWithLifecycle()observeAsState()The migration is mechanical:
// Before
class LoginViewModel : ViewModel() {
private val _state = MutableLiveData<LoginUiState>()
val state: LiveData<LoginUiState> = _state
}
// After
class LoginViewModel : ViewModel() {
private val _state = MutableStateFlow<LoginUiState>(LoginUiState.Idle)
val state: StateFlow<LoginUiState> = _state.asStateFlow()
}In Compose, replace
observeAsState()collectAsStateWithLifecycle()lifecycle-runtime-composeIn non-Compose Views, replace
observe()viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.state.collect { state ->
// update UI
}
}
}Legacy codebases with no immediate migration plan. Mixed Compose/View codebases where the LiveData + DataBinding wiring would cost more to remove than keep. If it's already working and the app is stable, the migration risk may not be worth it.
For new code: StateFlow, always.
It's not about following Google's recommendations. It's that StateFlow composes better. You can
combinefiltermapThe more complex your state management gets, the more the functional operators on Flow save you. LiveData has no equivalent.
After switching 22+ apps: the migration is low risk, the upside compounds over time, and there's no scenario where I'd choose LiveData for new work.
Sudarshan Chaudhari
AI Systems Builder / Product Engineer
Bangkok, Thailand
Solo Android developer with 13+ years in QA, building Android apps, AI automation systems, and developer tools at SudarshanTechLabs.
Related Posts
Related Apps
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
Building something? Available for Android dev and QA consulting.
Work with meComments — powered by Giscus
Real-time family location sharing — Firebase Realtime DB for sub-second propagation, WorkManager + ForegroundService for OS-compliant background collection, geofencing via Google Maps API.
ReadPrivate dream journal — structured entry capture, pattern tagging, and optional Claude-powered insight generation. All data stays on-device by default.
ReadWorkout tracker — exercise logging with set/rep/weight history, goal progression, and local Room DB persistence. No account, no cloud sync required.
Read