The Model-View-ViewModel (MVVM) architecture is a powerful pattern used in Android development to separate responsibilities and enhance code maintainability. With the integration of Kotlin Flow, managing data streams becomes seamless and efficient.
Model
In MVVM, the Model represents the data layer and can include data models and services.
View
The View, which includes Activities and Fragments, focuses solely on view logic and observes data changes from the ViewModel.
@Composable
fun Screen(viewModel: MainViewModel) {
val uiState = viewModel.uiState.collectAsStateWithLifecycle()
when (val uiStateValue = uiState.value) {
is MainUiState.Success -> MainList(list = uiStateValue.facts)
is MainUiState.Error -> Message(name = uiStateValue.message)
MainUiState.Init -> Message(name = "Welcome")
MainUiState.Loading -> Message(name = "Loading")
}
}
ViewModel
The ViewModel serves as the bridge between the Model and the View. It interacts with the Model and updates the View accordingly.
sealed class MainUiState {
object Init : MainUiState()
object Loading : MainUiState()
data class Success(val facts: List<CatFact>) : MainUiState()
data class Error(val message: String) : MainUiState()
}
@HiltViewModel
class MainViewModel @Inject constructor(
private val catFactsRepository: CatFactsRepository
) : ViewModel() {
private val _uiState = MutableStateFlow<MainUiState>(MainUiState.Init)
val uiState: StateFlow<MainUiState> = _uiState
init {
loadFacts()
}
private fun loadFacts() {
_uiState.value = MainUiState.Loading
viewModelScope.launch {
val response = catFactsRepository.facts()
if (response is Success) {
_uiState.value = MainUiState.Success(response.value)
} else {
_uiState.value = MainUiState.Error("Couldn't fetch")
}
}
}
}
Kotlin Flow is integrated seamlessly into this architecture, allowing easy manipulation and transformation of data at each layer. Flows can be created in the lower layers, near the API services. These flows can be passed through each layer for data transformation and ultimately collected from the ViewModels.
The layers in MVVM and Flow integration are as follows:
1. Services: These classes handle data sending and receiving. They can also map response data into DTO objects.
2. Repositories: Business logic is applied to the flows received from the Services. Repositories serve as the intermediaries between the Services and Use Cases.
3. Use Cases: Use cases reflect user interactions and define the application logic. They utilize the flows from the Repositories and perform actions accordingly.
4. ViewModels: These controllers serve as the entry point for the Android Framework. ViewModels launch and collect data from flows. They manage the lifecycle of the flows.
5. Activities/Fragments: These UI managers observe changes from ViewModels and update the UI components accordingly. Activities and Fragments should focus solely on view-related logic.
By following the Clean Architecture principles, such as separation of concerns and loose coupling, MVVM with Kotlin and Flows becomes a powerful combination for developing robust and maintainable Android applications. Effortless maintenance and easy testing are achieved through the well-defined responsibilities of each layer.
You can check out the sample repo on GitHub directly.
Leave a Reply