Search code examples
androidandroid-viewmodelandroid-navigation

What is the difference between navGraphViewModels and activityViewModels?


I know about SharedViewModel(by activityviewModel) how to share data between ViewModels.

But recently I also learned about navGraphViewModels.

I've tried both methods in my code using Navigation Component, but there doesn't seem to be much difference.

Both by activityViewModels and by navGraphViewModels confirmed that the data of screen B is maintained even if it is returned to screen B after moving to screen A.

What is the difference between these two?


enter image description here

enter image description here

<?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/main_graph"
    app:startDestination="@id/calendarFragment">

    <fragment
        android:id="@+id/calendarFragment"
        android:name="com.example.lightweight.presentation.ui.calendar.CalendarFragment"
        android:label="fragment_calendar"
        tools:layout="@layout/fragment_calendar" />

    <fragment
        android:id="@+id/dailyWorkoutLogFragment"
        android:name="com.example.lightweight.presentation.ui.write.DailyWorkoutLogFragment"
        android:label="fragment_daily_workout_log"
        tools:layout="@layout/fragment_daily_workout_log" >
        <action
            android:id="@+id/action_dailyWorkoutLogFragment_to_navigation"
            app:destination="@id/navigation" />
    </fragment>
    <navigation android:id="@+id/navigation"
        app:startDestination="@id/addRoutine">
        <fragment
            android:id="@+id/workoutListTabFragment"
            android:name="com.example.lightweight.presentation.ui.write.WorkoutListTabFragment"
            android:label="WorkoutListTabFragment"
            tools:layout="@layout/fragment_workout_list_tab">
            <action
                android:id="@+id/action_workoutListTabFragment_to_writeDetailFragment"
                app:destination="@id/writeDetailFragment" />
        </fragment>
        <fragment
            android:id="@+id/writeDetailFragment"
            android:name="com.example.lightweight.presentation.ui.write.WriteDetailFragment"
            android:label="fragment_write_detail"
            tools:layout="@layout/fragment_write_detail">
            <argument
                android:name="workout"
                android:defaultValue="@null"
                app:argType="string"
                app:nullable="true" />
            <action
                android:id="@+id/action_writeDetailFragment_to_addRoutine"
                app:destination="@id/addRoutine" />
        </fragment>
        <fragment
            android:id="@+id/addRoutine"
            android:name="com.example.lightweight.presentation.ui.write.AddRoutineFragment"
            android:label="fragment_add_routine"
            tools:layout="@layout/fragment_add_routine">

            <action
                android:id="@+id/action_addRoutine_to_workoutListTabFragment"
                app:destination="@id/workoutListTabFragment" />
        </fragment>
    </navigation>
</navigation>

Solution

  • activityViewModels() returns the view Model which is Scoped to Activity . Thats means all the Child fragments of this Activity will be sharing the same Instance of ViewModel when created by activityViewModels().

    When created by navGraphViewModels() the ViewModel is Scoped to navigation graph . it accepts a navGraphId: @IdRes Int of Subgraph . this is helpful When you do not want to Share Viewmodel b/w all the fragments and just b/w fragments of certain module for example Login/register.

    In single Activity Architecture You might want a ViewModel scoped to SignIn/SignUp graph but not for all other screens . in this case you can use navGraphViewModels with Sub-graph id and Share same instance only b/w the component of that graph only.

    If you have a single Graph and use root as navGraphId for navGraphViewModels then both navGraphViewModels() and activityViewModels() will end up having same scope.