I'm working on an Android application using Jetpack Compose and the MVVM/MVI architecture. I have a BaseViewModel class that all of my ViewModels extend. This class handles the associated State, Event, and Effect for each screen using generics. Here is the BaseViewModel class:
interface ViewEvent
interface ViewState
interface ViewSideEffect
abstract class BaseViewModel<UiState: ViewState, Event: ViewEvent, Effect: ViewSideEffect>: ViewModel() {
// Handling State
private val initialState: UiState by lazy { setInitialState() }
abstract fun setInitialState(): UiState
protected fun setState(reducer: UiState.() -> UiState) {
val newState = viewState.value.reducer()
_viewState.value = newState
}
private val _viewState: MutableState<UiState> = mutableStateOf(initialState)
val viewState: State<UiState> = _viewState
// Handling Event
private val _event: MutableSharedFlow<Event> = MutableSharedFlow()
abstract fun handleEvents(event: Event)
init {
subscribeToEvents()
}
private fun subscribeToEvents() {
viewModelScope.launch {
_event.collect { handleEvents(it) }
}
}
fun setEvent(event: Event) {
viewModelScope.launch {
_event.emit(event)
}
}
// Handling Effect
private val _effect: Channel<Effect> = Channel()
val effect = _effect.receiveAsFlow()
protected fun setEffect(builder: () -> Effect) {
val effectValue = builder()
viewModelScope.launch {
_effect.send(effectValue)
}
}
}
The challenge arises when I want to use a shared ViewModel across multiple screens. For instance, I have a main screen with four buttons, each navigating to a related screen where the user fills part of a form. I need to gather this data and send it to the server when the user taps the submit button on the main screen.
I attempted to create a CommonEffect, CommonEvent, and CommonState and passed these interfaces as generics to the CommonViewModel. However, this approach seems messy and leads to issues, especially with UI updates.
I'm looking for advice on whether using a shared ViewModel across these screens is a best practice. If so, how should I implement it effectively considering the challenges with generics and UI updates?
Thank you in advance.