0

I read a blog article about how to use Android Architecture component in a real application titled Using Navigation Architecture Component in a large banking app

In the section How to navigate from ViewModels? however, there is one thing I don't understand. A command is defined as follows:

sealed class NavigationCommand {
  data class To(val directions: NavDirections): NavigationCommand()
  object Back: NavigationCommand()
  data class BackTo(val destinationId: Int): NavigationCommand()
  object ToRoot: NavigationCommand()
}

What I don't understand about this is, that inside of NavigationCommand it actually uses NavigationCommand like in data class To(val directions: NavDirections): NavigationCommand() again - wouldn't this end up in infinite recursion? Also, what does it mean to use an objectlike in object Back: NavigationCommand()?

stefan.at.kotlin
  • 15,347
  • 38
  • 147
  • 270

3 Answers3

1

I also read that article. As my understand:

sealed class NavigationCommand {
  data class To(val directions: NavDirections): NavigationCommand()
  object Back: NavigationCommand()
  data class BackTo(val destinationId: Int): NavigationCommand()
  object ToRoot: NavigationCommand()
}

That provides all actions can do in one situation. For example your graph have some fragments: S -> A -> B -> C -> D.

Now, you are in the Fragment C. You may want to do one of these actions:

  1. I want to navigate to D -> sendCommand: NavigationCommand.To(R.id.Id_Of_D)
  2. I want to navigate to the previous screen: -> sendCommand: NavigationCommand.Back
  3. I want to navigate back to A -> sendCommand: NavigationCommand.BackTo(R.id.Id_Of_A)
  4. I want to navigate back to the root of the current graph: -> sendCommand: NavigationCommand.ToRoot)

That it is.

There are commands you need to send from view model, after that the view model will fire that event to the live data. Next, the MOST IMPORTANT HERE - How is that event is comsumed. You have to take a look at the BaseFragment

override fun onActivityCreated(savedInstanceState: Bundle?) {
  super.onActivityCreated(savedInstanceState)
  vm?.navigationCommands?.observe { command ->
    when (command) {
      is NavigationCommand.To ->      
        findNavController().navigate(command.directions)
        …

In the article, there is small implement. But for full implementation, it will look like this one: BaseFragment.kt

open class BaseFragment : Fragment() {
    open val baseViewModel: BaseViewModel? = null

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        baseViewModel?.navigationCommands?.observeEventNonNull(viewLifecycleOwner) { command ->
            val navController = findNavController()
            when (command) {
                is NavigationCommand.To -> navController.navigate(command.directions)
                NavigationCommand.Back -> navController.popBackStack()
                is NavigationCommand.BackTo ->
                    navController.popBackStack(command.destinationId, false)
                NavigationCommand.ToRoot ->
                    navController.popBackStack(navController.graph.startDestination, false)
            }
        }
    }
}

So, till now, you will see, all the events we post in the view model to navigationCommands is handled here.

Have a nice coding!

quangson91
  • 1,044
  • 1
  • 16
  • 30
  • Keep in mind that you never need to extends `NavigationCommand`. You just use it by passing the correct parameters - the direction. – quangson91 Aug 31 '20 at 11:06
0

it actually uses NavigationCommand

This is the Kotlin mechanism for extension, the class after the : character is simply the class you are extending. In this case, the class being extended is marked as sealed - a way to make classes enumerable sealed classes

You can read about objects here, in this case an object is used in place of a class as no arguments are required to be passed with this particular NavigationCommand

Ivan Wooll
  • 4,145
  • 3
  • 23
  • 34
0

The code is written in Kotlin language. It uses sealed class to define all commands. To learn more about sealed classes use this link

  1. So the thing it does is that it defines class NavigationCommand and then defines inner class To which extends from NavigationCommand. Calling NavigationCommand() during the defining To class is the same as calling super constructor. For example the same thing for To class in Java could be written like this:
public class NavigationCommand {

    public static class To extends NavigationCommand {

        private NavDirections directions;

        public To(NavDirections directions) {
            super(); // This is the same as calling "NavigationCommand()" in To class definition
            this.directions = directions;
        }

    }

}
  1. object keyword in Kotlin creates singleton class. To learn more about object keyword use this link
gevondov
  • 166
  • 6