ViewModel is not recreated after full destroy of the Fragment (Jetpack Navigation + Dagger 2)

Viewed 19

I have the following situation: there's a bottom navigation in the app's activity. Each tab of the navigation contains it's own graph. It looks in the following way:

  A --- C
  |     |
\  /   \  /
 \/     \/
  B      D

A and C in this case - roots of the graphs, B and D - nested screens.

The problem is that when I switch to tab C, then navigate to screen D, than go back to A and go back to D again (as backstack is kept), I cannot go back to C as I am redirected back to D. I discovered, why does it happen. When I redirect from C to D at the first time, I add value to LiveData and then handle it:

class MasFragment {

    @Inject
    internal lateinit var viewModelFactory: ViewModelFactory
    private val viewModel by viewModels<MasViewModel> { viewModelFactory }

    override fun onCreate(state: Bundle?) {
        super.onCreate(state)
        viewModel.apply {
            observe(navigation, ::handleRoute)
        }
    }

    private fun handleRoute(route: Route?) {
        when (route) {
            is Route.ProfileEdit.LoanHistory -> findNavController().navigate(
                MasFragmentDirections.actionMasToLoanhistory()
            )
        }
    }
}

class MasViewModel @Inject constructor() : BaseViewModel() {

    private val _navigation = MutableLiveData<Route>()
    internal val navigation: LiveData<Route> = _navigation

    internal fun openLoanHistoryInfo() = run {
        _navigation.value = Route.ProfileEdit.LoanHistory
    }
}

So, when I navigate from D to C after tab switching onCreate for MasFragment is called, but viewModel contains old values in liveData (as it is the same object which was after first opening of C). so redirect happens in onCreate without emitting new event. I cannot understand, why viewModel is not recreated and here I need some help. Here's my graph:

@Singleton
@Component(
    modules = [
        AndroidSupportInjectionModule::class,
        ActivityBuilderModule::class,
    ]
)
interface AppComponent : AndroidInjector<App> {

    @Component.Factory
    interface Factory {
        fun build(@BindsInstance application: Application): AppComponent
    }
}

@Module(
    includes = [
        ViewModelModule::class
    ]
)
abstract class ActivityBuilderModule {

    @ActivityScope
    @ContributesAndroidInjector(modules = [PrivateAreaModule::class])
    internal abstract fun bindMainActivity(): MainActivity

}

@Module
abstract class ViewModelModule {

    @Binds
    internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

}

@Module(includes = [PAEditModule::class])
abstract class PrivateAreaModule {
    @PrivateAreaScope
    @ContributesAndroidInjector(modules = [MasModule::class])
    internal abstract fun bindMasFragment(): MasFragment
}

@Module
abstract class MasModule {

    @Binds
    @IntoMap
    @ViewModelKey(value = MasViewModel::class)
    internal abstract fun bindMasViewModel(viewModel: MasViewModel): ViewModel

}

class ViewModelFactory
@Inject
constructor(
    private val viewModels: MutableMap<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        val viewModelProvider = viewModels[modelClass]
            ?: throw IllegalArgumentException("Unknown ViewModel class $modelClass")
        return viewModelProvider.get() as T
    }

}

Thanks in advance for any help

0 Answers
Related