Skip to content Skip to sidebar Skip to footer

How To Use Android Navigation Without Binding To Ui In Viewmodel (mvvm)?

I am using android navigation that was presented at Google I/O 2018 and it seems like I can use it by binding to some view or by using NavHost to get it from Fragment. But what I n

Solution 1:

How can I navigate from ViewModel?

The answer is please don't. ViewModel is designed to store and manage UI-related data.

New Answer

In my previous answers, I said that we shouldn't navigate from ViewModel, and the reason is because to navigate, ViewModel must have references to Activities/Fragments, which I believe (maybe not the best, but still I believe it) is never a good idea.

But, in recommended app architecture from Google, it mentions that we should drive UI from model. And after I think, what do they mean with this?

So I check a sample from "android-architecture", and I found some interesting way how Google did it.

Please check here: todo-mvvm-databinding

As it turns out, they indeed drive UI from model. But how?

  1. They created an interface TasksNavigator that basically just a navigation interface.
  2. Then in the TasksViewModel, they have this reference to TaskNavigator so they can drive UI without having reference to Activities / Fragments directly.
  3. Finally, TasksActivity implemented TasksNavigator to provide detail on each navigation action, and then set navigator to TasksViewModel.

Solution 2:

There are two ways I can recommend doing this.

  1. Use LiveData to communicate and tell the fragment to navigate.
  2. Create a class called Router and this can contain your navigation logic and reference to the fragment or navigation component. ViewModel can communicate with the router class to navigate.

Solution 3:

You can use an optional custom enum type and observe changes in your view:

enumclassNavigationDestination{
    SHOW_TOUR, SHOW_CODE_FRAGMENT
}

classCaptionViewModel(app: Application) : AndroidViewModel(app) {
    privateval dealerProfile = DealerProfile(getApplication())
    val TAG = "REGDEB"privateval _destination = MutableLiveData<NavigationDestination?>(null)
    val destination: LiveData<NavigationDestination?> get() = _destination
    
    funsetDestinationToNull() {
        _destination.value = null
    }
    

    funstart(){
        if(dealerProfile.getOperatorId().isEmpty()){
            if(dealerProfile.isFirstTimeLaunch()){
                Log.d(TAG, "First Time Launch")
                _destination.value = NavigationDestination.SHOW_TOUR
            }else{
                _destination.value = NavigationDestination.SHOW_CODE_FRAGMENT
                Log.d(TAG, "Show Code Fragment")

            }
        }
    }
}

And then in your view observe the viewModel destination variable:

viewModel.destination.observe(this, Observer { status ->
            if (status != null) {
                viewModel.setDestinationToNull()
                status?.let {
                    when (status) {
                        NavigationDestination.SHOW_TOUR -> {
                            // Navigate to your fragment
                        }
                        NavigationDestination.SHOW_CODE_FRAGMENT -> {
                            // Navigate to your fragment
                        }
                    }
                })
            }

If you only have one destination you can just use a Boolean rather than the enum.

Post a Comment for "How To Use Android Navigation Without Binding To Ui In Viewmodel (mvvm)?"