Search code examples
androidandroid-jetpack-composeandroid-jetpack-navigationjetpack-compose-navigation

Passing model between destinations


I'm working on application which uses Jetpack Compose with Jetpack Compose Navigation. In one view (destination) I'm displaying list on entries (let's call it View A with Model A). From this view user can go to creation view (View B with Model B), where new entry can be created. After successfull creation, I want to update list in Model A, so user don't need to refresh View A after going back to see newly created entry.

Is it possible to pass ViewModel class between navigation destinations using NavHost like this or in any other way?


Solution

  • As per the Thinking in Compose guide:

    your composables are responsible for transforming the current application state into a UI every time the observable data updates.

    That application state is the source of truth. This matches the Guide to app architecture, where your state is owned by lower level components that are responsible for the actual fetching, storing and caching of data, which is then exposed to the UI layer. This layer responsible for fetching, storing, and caching data is often called the 'repository layer'.

    That means that directly passing snapshots of data between destinations in your navigation graph is exactly the wrong way to approach the problem: it creates a source of truth problem (do you trust the snapshot you sent between destinations or the repository?). The answer is always the same: your repository should always be the source of truth and you should never be passing snapshots of data between destinations. In this way, every screen that uses the repository as its source of truth automatically has the most up to date information and there is never a need to 'refresh' your data.

    So your architecture would include three layers:

    • A single repository that owns your list of entries. The most simple part of this may just be the list held in memory as a mutableStateOf<List<Entry>>() that you update when the data changes with a new list. This class would be responsible for talking to the server, caching locally, etc.
    • (optionally, and a best practice) a layer of ViewModels, one for Screen A and one for Screen B that expose only the sets of methods from the repository specifically needed for that screen (i.e., your ViewModel A might expose a getEntries(), while ViewModel B might expose a createEntry(Entry) method.
    • Screen A and B focus solely on displaying the data retrieved from their associated ViewModel. As both are talking to the same repository layer, Screen B creating an entry will update the list that Screen A will retrieve its data from.