Don't expose Mutable Flow Types
Tags: android, build, gradle, performance
Published: 2023-07-23 22:36:23

---
title: Don't expose Mutable Flow Types
published: true
cover_image: https://s3-us-west-2.amazonaws.com/my-blogresources/IMAG1121.jpg
description: Use best practices to avoid exposing mutable flow types
tags: android, build, gradle, performance
series: Quality Quest
---
One of the recommendation in designing UI layer from the Android's guide to app architecture is to use '**Uni-Directional Data Flow**'. This is achieved by viewModels exposing UI state via observer pattern and receive events from UI via callbacks. 

One of the best practice in exposing the UI state is to use immutable data types like `LiveData` or `StateFlow`. But, sometimes, we may be tempted to use `MutableStateFlow` or `MutableSharedFlow` to expose the UI state. While they are very convenient for storing and adding updates of some data structures in event-driven paradigm & useful to manage such objects inside some class, it’s not recommended to expose them outside of the class.

## Why

When properties of the types `MutableStateFlow` or `MutableSharedFlow` are accessible from outside of a class, data updates cannot be verified properly anymore.

```kotlin
val isBiometricEnabled = MutableStateFlow(false)
```

In the above example, the value of `isBiometricEnabled` can be changed from outside of the class. It is generally recommended to have only one class responsible for updating these flows, otherwise inconsistency issues and problems with maintainability, as well as bugs may be introduced.

## What to do

To restrict write access, `StateFlow` or `SharedFlow` should be used together with `private MutableStateFlow` or `MutableSharedFlow` fields.

- If the variable is used only for reading, change its type to `StateFlow` or `SharedFlow`
- If the variable is used for writing, change its type to `private MutableStateFlow` or `private MutableSharedFlow` and add a `public` property with `StateFlow` or `SharedFlow` type that exposes the value of the `private` field

## How to do

Here's one way of refactoring the code.

1. Find the usages of the variable in question (i.e., one that has `MutableStateFlow` or `MutableSharedFlow` type)
2. If the variable is used only for reading, change its type to `StateFlow` or `SharedFlow`
3. If the variable is used for reading & writing,
  - Create a new variable with `StateFlow` or `SharedFlow` type that reads from the `MutableStateFlow` or `MutableSharedFlow` variable (use some naming convention to indicate that naming is temporary)

    ```kotlin
    val isBiometricEnabled = MutableStateFlow(false)
    val tempIsBiometricEnabled:StateFlow<Boolean> = isBiometricEnabled.asStateFlow()
    ```

  - Replace 'read' usages with the new variable
  - Change the type of the `MutableStateFlow` or `MutableSharedFlow` variable to `private` & rename it to indicate that it is `private`

    ```kotlin
    private val _isBiometricEnabled = MutableStateFlow(false)
    val tempIsBiometricEnabled:StateFlow<Boolean> = _isBiometricEnabled.asStateFlow()
    ```

  - Fix the naming of the new variable to match the naming convention

    ```kotlin
    private val _isBiometricEnabled = MutableStateFlow(false)
    val isBiometricEnabled:StateFlow<Boolean> = _isBiometricEnabled.asStateFlow()
    ```

  - Check the usages to verify that `isBiometricEnabled` is not used for writing anywhere outside of the class and `_isBiometricEnabled` is not exposed outside of the class

## References

Here are some references to the articles that I found useful

- [coroutines-best-practices-mutable-types](https://developer.android.com/kotlin/coroutines/coroutines-best-practices#mutable-types)

---