I'm currently working on an Android application utilizing the MVI (Model-View-Intent) architecture. In my ViewModel, I'm using a MutableStateFlow to manage the UI state. I want to optimize my code to prevent repetitive work when checking response requests in my ViewModel's state.
I've implemented the following approach to handle response requests in my ViewModel:
@HiltViewModel
class ListViewModel @Inject constructor(private val repository: ListRepository) : ViewModel() {
val intentChannel = Channel<ListIntent>()
private val _state = MutableStateFlow<ListState>(ListState.Idle)
val state: StateFlow<ListState> get() = _state
init {
handleIntents()
}
private fun handleIntents() = viewModelScope.launch {
intentChannel.consumeAsFlow().collect { intent ->
when (intent) {
is ListIntent.LoadFiltersLetters -> fetchingFiltersList()
is ListIntent.LoadRandom -> fetchingRandomFood()
is ListIntent.LoadCategoriesList -> fetchingCategoriesList()
is ListIntent.LoadFoods -> fetchingFoodsList(intent.letter)
is ListIntent.LoadSearchFoods -> fetchingSearchFood(intent.search)
is ListIntent.LoadFoodByCategory -> fetchingFoodsByCategory(intent.category)
}
}
}
private fun fetchingFoodsByCategory(category: String) = viewModelScope.launch {
val response = repository.foodByCategory(category)
_state.emit(ListState.LoadingFoods)
when (response.code()) {
in 200..202 -> {
_state.value = if (response.body()!!.meals != null) {
ListState.FoodsList(response.body()!!.meals!!)
} else {
ListState.Empty
}
}
in 400..499 -> {
_state.emit(ListState.Error(""))
}
in 500..599 -> {
_state.emit(ListState.Error(""))
}
}
}
private fun fetchingSearchFood(search: String) = viewModelScope.launch {
val response = repository.searchFood(search)
_state.emit(ListState.LoadingFoods)
when (response.code()) {
in 200..202 -> {
_state.value = if (response.body()!!.meals != null) {
ListState.FoodsList(response.body()!!.meals!!)
} else {
ListState.Empty
}
}
in 400..499 -> {
_state.emit(ListState.Error(""))
}
in 500..599 -> {
_state.emit(ListState.Error(""))
}
}
}
private fun fetchingFoodsList(letter: String) = viewModelScope.launch {
val response = repository.foodsList(letter)
_state.emit(ListState.LoadingFoods)
when (response.code()) {
in 200..202 -> {
_state.value = if (response.body()!!.meals != null) {
ListState.FoodsList(response.body()!!.meals!!)
} else {
ListState.Empty
}
}
in 400..499 -> {
_state.emit(ListState.Error(""))
}
in 500..599 -> {
_state.emit(ListState.Error(""))
}
}
}
private fun fetchingCategoriesList() = viewModelScope.launch {
val response = repository.categoriesList()
_state.emit(ListState.LoadingCategory)
when (response.code()) {
in 200..202 -> {
_state.emit(ListState.CategoriesList(response.body()!!.categories))
}
in 400..499 -> {
_state.emit(ListState.Error(""))
}
in 500..599 -> {
_state.emit(ListState.Error(""))
}
}
}
private suspend fun fetchingRandomFood() {
val response = repository.randomFood()
when (response.code()) {
in 200..202 -> {
_state.emit(ListState.RandomFood(response.body()?.meals?.get(0)))
}
in 400..499 -> {
_state.emit(ListState.Error(""))
}
in 500..599 -> {
_state.emit(ListState.Error(""))
}
}
}
private suspend fun fetchingFiltersList() {
val list = listOf('A'..'Z').flatten().toMutableList()
_state.emit(ListState.FilterLetters(list))
}
}
when (response.code()) {
in 200..202 -> {
}
in 400..499 -> {
}
in 500..599 -> {
}
}
However, I find myself repeating similar code for different functions, which is not optimal I've heard that using coroutines and flows can help in avoiding this repetition. Could you please guide me on how to improve this code using coroutines and flows to minimize redundancy while efficiently handling response requests? Your insights and code examples would be greatly appreciated. Thank you!
I use mvi architecture
when (response.code()) {
in 200..202 -> {
}
in 400..499 -> {
}
in 500..599 -> {
}
}
I want to do this in the ViewModel, not in the repository, and avoid duplicate code