Clean way to share data between viewModels


I'm trying to follow Google's clean architecture guidelines.

I have a navigation subgraph with multiple pages corresponding to stages of filling a form.

Each page has it's own viewModel.

On the last screen I need to send data from the form to app's data layer which sends it to server.

How should I share the form object between viewModels?

I see such options here:

  • Create Form model and FormRepository in app's data layer and inject it to viewModels. I don't like it because knowledge about form is not exclusive for feature module anymore and appears in data layer, though it is basically a UI state
  • Use one viewModel for all stages. I don't like it because some stages do some data retrieval and input validation that is not relevant for others.
  • Create FormHolder singleton in feature module, that is injected to all VMs. I'm not sure about it because I'm trying to follow architecture guidelines.

What should I do?

1
Jul 15 at 6:50 AM
User AvatarAndrey Golubev
#android#mvvm#android-jetpack-compose#clean-architecture

Accepted Answer

Use a ViewModel scoped to the Navigation Graph (per subgraph) AND delegate logic

How to do it:

  1. Create a FormViewModel scoped to the navigation subgraph (not individual screens).

    • This acts as the shared state holder.
  2. Each screen still uses its own ScreenViewModel, but it reads from/writes to the FormViewModel.

  3. Validation and retrieval logic stay in screen ViewModels.

  4. Only FormViewModel talks to domain layer when submitting the final form.

// Shared ViewModel scoped to the subgraph
class FormViewModel @Inject constructor() : ViewModel() {
    var formState = mutableStateOf(FormData())
    fun updatePart1(data: Part1) { formState.value = formState.value.copy(part1 = data) }
    fun submitForm() { /* call useCase to submit */ }
}

// Each screen has its own logic
class Step1ViewModel @Inject constructor(
    private val formViewModel: FormViewModel // Injected via navGraphViewModels()
) : ViewModel() {
    fun onNext(input: Input) {
        // validate and update shared state
        formViewModel.updatePart1(convert(input))
    }
}

Navigation-Scoped ViewModel:

val formViewModel: FormViewModel by navGraphViewModels(R.id.formGraph) {
    defaultViewModelProviderFactory
}
User AvatarSanjeev Pal
Jul 15 at 7:00 AM
3