1

Folks I am stuck engineering a proper solution to access a viewModel scoped to a nav graph , from a button that exists in the TopAppBar in a compose application

Scaffold{
  TopAppBar-> Contains the Save Button 
  Body-> 
   BioDataGraph() -> Contains 5 screens to gather biodata information , and a viewmodel scoped to the graph

 }
}

My BioDataViewModel looks like this

class BioDataViewModel{
fun gatherPersonalInformation()
fun gatherPhotos()
...
fun onSaveEverything()
}

The issue i came across is as i described above , how should i go about access the BioDataViewModel , such that i can invoke onSaveEverything when save is clicked in the TopAppBar.

What I have tried

private val performSave by mutableStateOf(false)
Scaffold(
    topBar = {
        TopAppBar(currentDestination){
         //save is clicked.
          performSave = true
         
        }
    })
{
     NavHost(
      navController = navController,
      startDestination = homeNavigationRoute,
      modifier = Modifier
        .padding(padding)
        .consumedWindowInsets(padding),
    ) {
      composable(route = bioDataRoute) {
        val viewModel = hiltViewModel<BioDataViewModel>()
        if (performSave){
          viewModel.onSaveEverything()
        }
        BioDataScreen(
          viewModel
        )
      }
    }

}

The problem with the approach above is that how and when should i reset the state of performSave ? . Because if i do not set it to false; on every recomposition onSaveEverything would get called.

What would be the best way to engineer a solution for this ? . I checked to see if a similar situation was tackled in jetpack samples , but i found nothing there .

Muhammad Ahmed AbuTalib
  • 4,080
  • 4
  • 36
  • 59
  • You just want to set `performSave` to false?, I'm not sure if I understand you correctly, but why don't you just simply call `performSave = false` in one of the NavHost composable? – z.g.y Dec 03 '22 at 09:13
  • Or you want to call `viewModel.onSaveEverything()` in the `TopAppBar` ? – z.g.y Dec 03 '22 at 09:15

1 Answers1

0

I'm not sure if I understand you correctly, but you can define the BioDataViewModel in activity level, and you can access it in the TopAppBar like this

class MyActivity: ComponentActivity() {

    // BioDataViewModel definition here
    private val viewModel: BioDataViewModel by viewModels()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            Scaffold(
                topBar = {
                    TopAppBar(currentDestination) {
                        //save is clicked.
                        viewModel.onSaveEverything() // call onSaveEverything here
                    }
                })
            {
                ...
                ...
            }

       ...
       ...

Edit:

If you want to have the same instance of ViewModel from activity and NavGraph level, you can consider this, a reference from my other answer.

You can define the ViewModelStoreOwner in the navigation graph level.

NavHost(
    navController = navController,
    startDestination = homeNavigationRoute,
    modifier = Modifier
           .padding(padding)
           .consumedWindowInsets(padding),
) {

    val viewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
        "LocalViewModelStoreOwner not available"
    }

    composable(route = bioDataRoute) {

        val viewModel = hiltViewModel<BioDataViewModel>(viewModelStoreOwner)

        if (performSave){
            viewModel.onSaveEverything()
        }

        BioDataScreen(
            viewModel
        )
    }
}
z.g.y
  • 5,512
  • 4
  • 10
  • 36
  • yes , but mate I have to scope the BioDataViewModel to the graph . Activity scoping it would be really wasteful for me – Muhammad Ahmed AbuTalib Dec 03 '22 at 10:48
  • Ahh so you want same instance of BioDataViewModel in activity and the same in nav graph?, also what do you mean by "wasteful"? – z.g.y Dec 03 '22 at 10:48
  • I'm little bit confused as to what you want to achieve here, but Ill just edit my answer and see if you find anything usefull from it – z.g.y Dec 03 '22 at 10:58