This is not how view models are supposed to be used.
A view model is not a model itself. A view model is named as such because it connects the view (the UI) with the models (the data sources). This pattern is also called Model–view–viewmodel (MVVM). There are many variations, but in essence the view model needs to asssemble all required data in one place so the UI can easily access it.
You will usually have one view model per screen. You will not have one view model for file access (like your FileModel), another view model for database access (like your DatabaseModel), and one view model for errors (like your ErrorModel). So the question you are asking is missing the point, this is not what you really want to do in the first place.
Instead, your view models should be specific to the content they provide. You may have a ProductsViewModel, an AccountViewModel, a CheckoutViewModel and so on - it all depends on the actual functionality of your app.
For example: If you need to read the products from your database to display them in the ProductsScreen composable, you would have a ProductsViewModel that would expose its state like this:
class ProductsViewModel : ViewModel() {
val state: StateFlow<ProductsUiState>
}
How exactly the data is read from the database depends on the database implementation, but if you want to handle errors here, you would eventually either have a list of products, or an error message. So ProductsUiState could look something like this:
sealed interface ProductsUiState {
data class Success(val products: List<Product>) : ProductsUiState
data class Error(val message: String) : ProductsUiState
}
Your composable can then decide what to do:
@Composable
fun ProductsScreen(viewModel: ProductsViewModel) {
val state = viewModel.state.collectAsStateWithLifecycle().value
when(state) {
is ProductsUiState.Success -> ListOfProducts(state.products)
is ProductsUiState.Error -> Text("Products couldn't be loaded: ${state.message}")
}
}
The key here is that errors are only relevant at the place where the data is actually needed that is now - due to the error - absent. So you don't need to have the error message present globally throughout your app. The above error, for example, is not relevant when the AccountScreen is currently displayed instead of the ProductsScreen. So the AccountViewModel never needs this error state in the first place. It suffices if that is solely encapsulated in the ProductsViewModel.
Final note: Although you are right with the assessment that the database access can fail, don't overcomplicate things in your UI logic. What would be the benefit for the user to know that (and why) the local database couldn't be read? Errors like these only help when the user can actually do something about it.
For example, when they switched off wifi then your app cannot access the server over the internet. In that case an error message informing the user about it is helpful: The user can then decide to switch wifi back on. But what should the user do to remedy the database error? In an Android app, for example, you would be better off simply crashing the app in that case. Then the user can decide to try again by restarting the app, clearing app data respectively reinstalling the app or buying a new device.
Your app does not need to gracefully handle corrupt local storage - be it caused by a software or a hardware defect. The solutions for these kind of errors are not specific to your app, so don't make it more complicated than it needs to be.