Scoping a viewmodel to multiple fragments (not activity) using the navigation component

前端 未结 3 1783
北荒
北荒 2020-12-05 19:24

I\'m using the navigation component, I want a view model to be shared between a few fragments but they should be cleared when I leave the fragments (hence not scoping them t

相关标签:
3条回答
  • 2020-12-05 19:56

    Here's a concrete example of Alex H's accepted answer.

    In your build.gradle (app)

    dependencies {
        def nav_version = "2.1.0"
        implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    }
    

    Example of view model

    class MyViewModel : ViewModel() { 
        val name: MutableLiveData<String> = MutableLiveData()
    }
    

    In your FirstFlowFragment.kt define

    val myViewModel: MyViewModel by navGraphViewModels(R.id.your_nested_nav_id)
    myViewModel.name.value = "Cool Name"
    

    And in your SecondFlowFragment.kt define

    val myViewModel: MyViewModel by navGraphViewModels(R.id.your_nested_nav_id)
    val name = myViewModel.name.value.orEmpty()
    Log.d("tag", "welcome $name!")
    

    Now the ViewModel is scoped in this nested fragment, shared state will be destroyed when nested nav is destroyed as well, no need to manually reset them.

    0 讨论(0)
  • 2020-12-05 20:08

    Yes, it's possible to scope a viewmodel to a navgraph now starting with androidx.navigation:*:2.1.0-alpha02. See the release notes here and an example of the API here. All you need to give is the R.id for your navgraph. I find it a bit annoying to use, though, because normally viewmodels are initialized in onCreate, which isn't possible with this scope because the nav controller isn't guaranteed to be set by your nav host fragment yet (I'm finding this is the case with configuration changes).

    Also, if you don't want your mainFragment to be part of that scope, I would suggest taking it out and maybe using a nested nav graph.

    0 讨论(0)
  • 2020-12-05 20:08

    so when i posted this the functionality was there but didn't quite work as expected, since then i now use this all the time and this question keeps getting more attention so thought i would post an up to date example,

    using

    //Navigation
    implementation "androidx.navigation:navigation-fragment:2.2.0-rc04"
    // Navigation UI
    implementation "androidx.navigation:navigation-ui:2.2.0-rc04"
    

    i get the view model store owner like this

    private ViewModelStoreOwner getStoreOwner() {
    
            NavController navController = Navigation
                    .findNavController(requireActivity(), R.id.root_navigator_fragment);
            return navController.getViewModelStoreOwner(R.id.root_navigator);
    }
    

    im using the one activity multiple fragments implementation, but using this i can effectively tie my view models to just the scoped fragments and with the new live data you can even limit that too

    the first id comes from the nav graphs fragment

    <?xml version="1.0" encoding="utf-8"?>
      <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    
        <fragment
          android:id="@+id/root_navigator_fragment"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:name="androidx.navigation.fragment.NavHostFragment"
          app:defaultNavHost="true"
          app:navGraph="@navigation/root_navigator"/>
    
      </FrameLayout>
    

    and the second comes from the id of the nav graph

      <?xml version="1.0" encoding="utf-8"?>
      <navigation xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/root_navigator"
        app:startDestination="@id/mainNavFragment">
    

    and then you can use it like so

    private void setUpSearchViewModel() {
        searchViewModel = new ViewModelProvider(getStoreOwner()).get(SearchViewModel.class);
    }
    
    0 讨论(0)
提交回复
热议问题