State Flow and Shared Flow in Kotlin
<h1>State Flow</h1>
<ul>
<li><code>StateFlow</code> is a state-holder observable flow that emits the current and new state updates to its collectors.</li>
<li>A SharedFlow that represents a read-only state with a single updatable data value that emits updates to the value to its collectors.</li>
<li>State flow is designed to be a more efficient and simplified version of Kotlin’s existing Flow library, with the key difference being that it represents a single value that can be updated over time, whereas Flow represents a sequence of values.</li>
<li>State flow uses a similar syntax to Flow, but instead of emitting a stream of values, it exposes a single value that can be updated using the <code>value</code> property. Changes to this value are automatically propagated to all observers of the state flow.</li>
<li>A state flow is a <em>hot</em> flow because its active instance exists independently of the presence of collectors.</li>
<li>A <code>StateFlow</code> is always active and in memory, and it becomes eligible for garbage collection only when there are no other references to it from a garbage collection root.</li>
<li>A mutable state flow is created using <code>MutableStateFlow(value)</code> constructor function with the initial value.</li>
<li>All methods of state flow are <strong>thread-safe</strong> and can be safely invoked from concurrent coroutines without external synchronization.</li>
</ul>
<p>Let’s understand this with an example. Suppose we are fecthing users list from server and then showing that on ui.</p>
<p>Step 1: Create model class</p>
<pre>
data class User(val id: Int, val name: String, val email: String)</pre>
<p>Step 2: Make api call in repo</p>
<pre>
class UserRepository {
suspend fun getUserById(userId: Int): User {
// make API call to fetch user data
val response = // make API call here
return response.toUser() // convert API response to User object
}
}</pre>
<p>Step 3: Make this call from ViewModel</p>
<pre>
class UserViewModel(private val repository: UserRepository) : ViewModel() {
private val _user = MutableStateFlow<User?>(null)
val user: StateFlow<User?> = _user
fun getUserById(userId: Int) = viewModelScope.launch {
_user.value = repository.getUserById(userId)
}
}</pre>
<p>Step 4: Observer into the activity</p>
<pre>
class UserFragment : Fragment() {
private val viewModel: UserViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val userId = arguments?.getInt("userId") ?: throw IllegalArgumentException("userId is required")
viewModel.getUserById(userId)
viewModel.user.onEach { user ->
userTextView.text = user?.name ?: "Loading..."
emailTextView.text = user?.email ?: ""
}.launchIn(viewLifecycleOwner.lifecycleScope)
}
}</pre>
<p>In this example, the fragment obtains the user ID from its arguments and calls <code>getUserById()</code> on the view model to fetch the user data. The <code>user</code> state flow is then observed using the <code>onEach()</code> function, which updates the UI with the user's name and email when it becomes available. Note that <code>launchIn()</code> is used to launch the flow in the fragment's <code>LifecycleScope</code>, which ensures that the flow is cancelled when the fragment is destroyed.</p>
<p><a href="https://levelup.gitconnected.com/state-flow-and-shared-flow-in-kotlin-f603c7aa7299">Read More</a></p>