I am building an app has has a lots of input fields so with those input fields I have to manage a lots of states in my viewModel.
Due to this my viewModel is a total mess. Can anyone guide me to handle these states efficiently with clean code.
The state management pattern that I am using is mentioned in android official documentation.
My viewModels looks like this-
@HiltViewModel
class CardsViewModel @Inject constructor(
private val repository: CardsRoomRepository
): ViewModel() {
private val _results = MutableStateFlow<List<CardsItems>>(emptyList())
val results: StateFlow<List<CardsItems>> = _results
private val _resultsForFavorites = MutableStateFlow<List<CardsItems>>(emptyList())
val resultsForFavorites: StateFlow<List<CardsItems>> = _resultsForFavorites
private val _resultsForSearch = MutableStateFlow<List<CardsItems>>(emptyList())
val resultsForSearch: StateFlow<List<CardsItems>> = _resultsForSearch
private val _switch = mutableStateOf(false)
var switch: State<Boolean> = _switch
fun setSwitch(newText: Boolean) {
_switch.value = newText
}
private val _searchQuery = mutableStateOf("")
val searchQuery: State<String> = _searchQuery
fun setSearchQuery(newText: String){
_searchQuery.value = newText
}
init {
getAllLoginsItems()
getAllFavoriteCardsItems()
}
private val _title = mutableStateOf("")
var title: State<String> = _title
fun setTitle(newText: String) {
_title.value = newText
}
private val _category = mutableStateOf(0)
val category: State<Int> = _category
fun setCategory(newText: Int) {
_category.value = newText
}
private val _cardNumber = mutableStateOf("")
val cardNumber: State<String> = _cardNumber
fun setCardNumber(newText: String) {
_cardNumber.value = newText
}
private val _cardHolderName = mutableStateOf("")
var cardHolderName: State<String> = _cardHolderName
fun setCardHolderName(newText: String) {
_cardHolderName.value = newText
}
private val _pinNumber = mutableStateOf("")
var pinNumber: State<String> = _pinNumber
fun setPinNumber(newText: String) {
_pinNumber.value = newText
}
private val _cvvNumber = mutableStateOf("")
var cvvNumber: State<String> = _cvvNumber
fun setCVVNumber(newText: String) {
_cvvNumber.value = newText
}
private val _issueDate = mutableStateOf("")
var issueDate: State<String> = _issueDate
fun setIssueDate(newText: String) {
_issueDate.value = newText
}
private val _expiryDate = mutableStateOf("")
var expiryDate: State<String> = _expiryDate
fun setExpiryDate(newText: String) {
_expiryDate.value = newText
}
....
}
And
@HiltViewModel
class OthersViewModel @Inject constructor(
private val repository: OthersRoomRepository
) : ViewModel() {
private val _results = MutableStateFlow<List<OthersItems>>(emptyList())
val results: StateFlow<List<OthersItems>> = _results
private val _resultsForFavorites = MutableStateFlow<List<OthersItems>>(emptyList())
val resultsForFavorites: StateFlow<List<OthersItems>> = _resultsForFavorites
private val _resultsForSearch = MutableStateFlow<List<OthersItems>>(emptyList())
val resultsForSearch: StateFlow<List<OthersItems>> = _resultsForSearch
private val _switch = mutableStateOf(false)
var switch: State<Boolean> = _switch
fun setSwitch(newText: Boolean) {
_switch.value = newText
}
private val _searchQuery = mutableStateOf("")
val searchQuery: State<String> = _searchQuery
fun setSearchQuery(newText: String) {
_searchQuery.value = newText
}
init {
getAllOthersItems()
getAllFavoriteOthersItems()
}
private val _title = mutableStateOf("")
var title: State<String> = _title
fun setTitle(newText: String) {
_title.value = newText
}
private val _category = mutableStateOf(0)
val category: State<Int> = _category
fun setCategory(newText: Int) {
_category.value = newText
}
private val _userName = mutableStateOf("")
val userName: State<String> = _userName
fun setUserName(newText: String) {
_userName.value = newText
}
private val _password = mutableStateOf("")
val password: State<String> = _password
fun setPassword(newText: String) {
_password.value = newText
}
private val _description = mutableStateOf("")
val description: State<String> = _description
fun setDescription(newText: String) {
_description.value = newText
}
private val _macAddress = mutableStateOf("")
val macAddress: State<String> = _macAddress
fun setMacAddress(newText: String) {
_macAddress.value = newText
}
....
}
I don't think there's any point in creating a setter for each property, in your example. It can be useful when you have some logic which not just updating the value.
You can move your states into separate classes. As long as you have them as state objects, updating them will trigger recomposition.
Let's say you have a CardView
which draw your card with number, name, etc. If you don't have it in a separate view, that's an other good practice to split your composables into small views. In addition to the convenience of splitting the data into chunks, it will help with reconfiguration and is much easier to read and develop.
So group all data that's being used by this view into CardData
:
class CardData {
val cardNumber = mutableStateOf("")
val cardHolderName = mutableStateOf("")
val pinNumber = mutableStateOf("")
val cvvNumber = mutableStateOf("")
val issueDate = mutableStateOf("")
val expiryDate = mutableStateOf("")
}
Store it in your view model:
@HiltViewModel
class CardsViewModel @Inject constructor(
private val repository: CardsRoomRepository
): ViewModel() {
...
val cardData = CardData()
}
And pass to your view:
@Composable
fun Screen(viewModel: CardsViewModel() = viewModel()) {
...
CardView(viewModel.cardData)
}
And if you're using these setters to pass to text fields, you can unwrap them like this:
@Composable
fun CardView(cardData: CardData) {
val (cardHolderName, cardHolderNameSetter) = cardData.cardHolderName
TextField(cardHolderName, cardHolderNameSetter)
}