0% found this document useful (0 votes)
64 views24 pages

Section 15 - SharedFlow and StateFlow

The document discusses different approaches for exposing Flows instead of LiveData in ViewModels. It analyzes exposing regular Flows, lifecycle-aware collecting, and exposing a 'hot' Flow using SharedFlow. Exposing a SharedFlow in the ViewModel is presented as the best approach as it avoids problems with configuration changes restarting the Flow.

Uploaded by

Think Box
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
64 views24 pages

Section 15 - SharedFlow and StateFlow

The document discusses different approaches for exposing Flows instead of LiveData in ViewModels. It analyzes exposing regular Flows, lifecycle-aware collecting, and exposing a 'hot' Flow using SharedFlow. Exposing a SharedFlow in the ViewModel is presented as the best approach as it avoids problems with configuration changes restarting the Flow.

Uploaded by

Think Box
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 24

StateFlow

and

SharedFlow
Module: “Basics of Kotlin Flow”

ViewModel
Activity
observes
LiveData<UiState>

Module: “StateFlow and SharedFlow”

ViewModel
Activity
collects
Flow<UiState>
Antipattern
using LiveData in other Layers
than the UI Layer
Advantages: Exposing Flows instead of LiveData in ViewModels
A Single type of observable data holder throughout your architecture

No knowledge about LiveData necessary

More ow operators

ViewModels are decoupled from Android Dependencies

Simpli ed testing
fl
fi
Disadvantages: Exposing Flows instead of LiveData in ViewModels

more “boilerplate” code in the view


Summary: Exposing Flows instead of LiveData in ViewModels

existing Code: 🤔

new Code: 🙂
Approach 1: Exposing regular ow

Activity ViewModel
lifecycleScope.launch {
viewModel.currentStockPriceAsFlow.collect { val currentStockPriceAsFlow: Flow<UiState>
render(uiState)
}
}

Problems ❌
• Flow Producer continues to run when the app is in background
• Activity receives emissions and renders UI when it is in the background
• Multiple collectors create multiple ows
• Con guration Change re-starts the ow
fi
fl
fl
fl
Approach 2: “lifecycle-aware” collecting coroutine

Activity ViewModel
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
val currentStockPriceAsFlow: Flow<UiState>
viewModel.currentStockPriceAsFlow.collect {
render(uiState)
}
}
}

Problems ❌
• Flow Producer continues to run when the app is in background
• Activity receives emissions and renders UI when it is in the background
• Multiple collectors create multiple ows
• Con guration Change re-starts the ow
fi
fl
fl
Approach 2: “lifecycle-aware” collecting coroutine

Activity ViewModel
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
val currentStockPriceAsFlow: Flow<UiState>
viewModel.currentStockPriceAsFlow.collect {
render(uiState)
}
}
}

Problems ❌
• Flow Producer continues to run when the app is in background
• Activity receives emissions and renders UI when it is in the background
• Multiple collectors create multiple ows
• Con guration Change re-starts the ow
fi
fl
fl
Approach 2: “lifecycle-aware” collecting coroutine

Activity ViewModel
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
val currentStockPriceAsFlow: Flow<UiState>
viewModel.currentStockPriceAsFlow.collect {
render(uiState)
}
}
}

Problems ❌
• Flow Producer continues to run when the app is in background ✅
• Activity receives emissions and renders UI when it is in the background
• Multiple collectors create multiple ows
• Con guration Change re-starts the ow
fi
fl
fl
Approach 2: “lifecycle-aware” collecting coroutine

Activity ViewModel
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
val currentStockPriceAsFlow: Flow<UiState>
viewModel.currentStockPriceAsFlow.collect {
render(uiState)
}
}
}

Problems ❌
• Flow Producer continues to run when the app is in background ✅
• Activity receives emissions and renders UI when it is in the background ✅
• Multiple collectors create multiple ows
• Con guration Change re-starts the ow
fi
fl
fl
Approach 3: Exposing a “hot” ow in the ViewModel
Activity ViewModel
lifecycleScope.launch { val currentStockPriceAsFlow: SharedFlow<UiState>
repeatOnLifecycle(Lifecycle.State.STARTED) { // = coldflow
viewModel.currentStockPriceAsFlow.collect { .shareIn(
render(uiState) scope = viewModelScope,
} started = SharingStarted.WhileSubscribed()
} )
}

Problems ❌
• Flow Producer continues to run when the app is in background ✅
• Activity receives emissions and renders UI when it is in the background ✅
• Multiple collectors create multiple ows
• Con guration Change re-starts the ow
fi
fl
fl
fl
Approach 3: Exposing a “hot” ow in the ViewModel
Activity ViewModel
lifecycleScope.launch { val currentStockPriceAsFlow: SharedFlow<UiState>
repeatOnLifecycle(Lifecycle.State.STARTED) { // = coldflow
viewModel.currentStockPriceAsFlow.collect { .shareIn(
render(uiState) scope = viewModelScope,
} started = SharingStarted.WhileSubscribed()
} )
}

Problems ❌
• Flow Producer continues to run when the app is in background ✅
• Activity receives emissions and renders UI when it is in the background ✅
• Multiple collectors create multiple ows ✅
• Con guration Change re-starts the ow
fi
fl
fl
fl
Cold Flows ❄ Hot Flows 🔥

• become active on collection • are active regardless of


whether there are collectors
• become inactive on
cancellation of the collecting • stay active even when there is
coroutine no more collector

• emit individual emissions to • emissions are shared


every collector between all collectors
con guration change without timeout

latestStockFlow
old Activity instance
onStop() stop collection stop collection

SharedFlow
t

new Activity instance start collection start collection


onCreate()

latestStockFlow
fi
con guration change with timeout of 5000ms

old Activity instance


onStop() stop collection

latestStockFlow
wait 5000 ms for new

SharedFlow
collectors
before stopping the
t upstream collection

new Activity instance start collection


onCreate()
fi
Problem: blank screen after orientation change

emission n

old Activity instance


onStop() stop collection

SharedFlow
t
new Activity instance start collection
onCreate()
blank
screen

emission n+1
Problem: blank screen after orientation change

emission n

old Activity instance


onStop() stop collection

SharedFlow
t
new Activity instance start collection
onCreate() emission n

emission n+1
Approach 3: Exposing a “hot” ow in the ViewModel
Activity ViewModel
val currentStockPriceAsFlow: SharedFlow<UiState>
lifecycleScope.launch {
// = coldflow
repeatOnLifecycle(Lifecycle.State.STARTED) {
.shareIn(
viewModel.currentStockPriceAsFlow.collect {
scope = viewModelScope,
render(uiState)
started = SharingStarted.WhileSubscribed(5000),
}
replay = 1
} )
}

Problems ❌
• Flow Producer continues to run when the app is in background ✅
• Activity receives emissions and renders UI when it is in the background ✅
• Multiple collectors create multiple ows ✅
• Con guration Change re-starts the ow
fi
fl
fl
fl
Approach 3: Exposing a “hot” ow in the ViewModel
Activity ViewModel
val currentStockPriceAsFlow: SharedFlow<UiState>
lifecycleScope.launch {
// = coldflow
repeatOnLifecycle(Lifecycle.State.STARTED) {
.shareIn(
viewModel.currentStockPriceAsFlow.collect {
scope = viewModelScope,
render(uiState)
started = SharingStarted.WhileSubscribed(5000),
}
replay = 1
} )
}

Problems ❌
• Flow Producer continues to run when the app is in background ✅
• Activity receives emissions and renders UI when it is in the background ✅
• Multiple collectors create multiple ows ✅
• Con guration Change re-starts the ow ✅
fi
fl
fl
fl
SharedFlow
VS 🤺

StateFlow
SharedFlow StateFlow

Initial Value No Yes

Replay Cache customizable xed size of 1

Emission of
yes no
subsequent equal values
fi
SharedFlow StateFlow
Initial Value No Yes

Replay Cache customisable xed size of 1

Emission of yes no
subsequent equal values

Rule of Thumb of Usage:


Whenever you want to use a hot ow, use a StateFlow by default.

StateFlows are more e cient when used for state

StateFlows provide convenient option to read and write its value in a non-suspending fashion by
synchronously accessing the .value property

Only if you have special requirements, switch to a SharedFlow.


fi
ffi
fl
Attention!

In Module 17 about “Concurrent Flows”, you will learn about an additional


di erence between SharedFlows and StateFlows.

With StateFlows, you can potentially “lose” emissions if you have a slow
collector.

You can nd more information about this behaviour in the lecture “Bu ers
in SharedFlow and StateFlow”
ff
fi
ff

You might also like