6

I have the following ViewModel

@HiltViewModel class ShareViewModel @Inject constructor( private val taskRepository: TaskRepository ): ViewModel() { private val searchAppBarStateMutableState: MutableState<SearchAppBarState> = mutableStateOf(SearchAppBarState.CLOSED) val searchAppBarState: State<SearchAppBarState> = searchAppBarStateMutableState private val listOfTaskMutableStateFlow = MutableStateFlow<List<TodoTaskEntity>>(emptyList()) val listOfTaskStateFlow = listOfTaskMutableStateFlow.asStateFlow() } 

I never expose mutableStateFlow as in the example above. And SonarLint will show a warning when doing this.

MutableStateFlow" and "MutableSharedFlow" should not be exposed 

So I apply the same technique to the mutableState

However, If I do like this below, I don't get any warning.

val searchAppBarStateMutableState: MutableState<SearchAppBarState> = mutableStateOf(SearchAppBarState.CLOSED) 

Just wondering what is the best practice for using MutableState with jetpack compose.

4
  • A common practice is to expose read-only states from viewmodels because you want to avoid the view modifying the state directly. I'd follow the same guideline with Compose. Commented May 22, 2022 at 15:52
  • stackoverflow.com/a/71817269/15880865 Commented May 22, 2022 at 16:29
  • The shortest version for mutable state is using delegation with private setter, like showed here. : State<SearchAppBarState> is also a possible variant if you need to pass a state for some reason. Not sure why your linter is not happy, the flow variant seems fine too. Commented May 22, 2022 at 17:55
  • Could it be that settings private variables need to have an underscore in front, " private val _listOfTaskMutableStateFlow.". Other than that seems all fine in regards to the lint issue. rules.sonarsource.com/kotlin/RSPEC-6305 Commented May 27, 2022 at 13:42

2 Answers 2

12
+500

To use mutableState with viewmodel, define mutableState with private setter inside viewmodel, ex -

var isVisible by mutableState(false) private set 

By doing above we can read the mutable state from outside of viewmodel but not update it. To update create a public function inside viewmodel, ex -

fun setVisibility(value: Boolean) { isVisible = value } 

By making a setter function we are following separation of concerns and having a single source of truth for editing the mutableState.

Sign up to request clarification or add additional context in comments.

Comments

2

I think the error is in that you are setting

 val searchAppBarState: State<SearchAppBarState> = searchAppBarStateMutableState 

if you want to share private value as not mutable you shouldn't set it equal rather you can use get modifier

 val searchAppBarState: State<SearchAppBarState> get() = searchAppBarStateMutableState 

Also it would be better to name it with underscore as many developers are used to like:

 private val _searchAppBarState: MutableState<SearchAppBarState> = mutableStateOf(SearchAppBarState.CLOSED) val searchAppBarState: State<SearchAppBarState> get() = _searchAppBarState 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.