【问题标题】:Understanding Command pattern for navigation from ViewModel了解从 ViewModel 导航的命令模式
【发布时间】:2020-07-02 07:58:20
【问题描述】:

我阅读了一篇关于如何在实际应用程序中使用 Android 架构组件的博客文章,标题为 Using Navigation Architecture Component in a large banking app

如何从 ViewModel 导航? 部分中,有一件事我不明白。命令定义如下:

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

对此我不明白的是,在NavigationCommand 内部,它实际上再次使用NavigationCommand,就像在data class To(val directions: NavDirections): NavigationCommand() 中一样——这不会导致无限递归吗?另外,在object Back: NavigationCommand() 中使用objectlike 是什么意思?

【问题讨论】:

    标签: android kotlin architecture android-viewmodel android-architecture-navigation


    【解决方案1】:

    它实际上使用了 NavigationCommand

    这是 Kotlin 的扩展机制,: 字符后面的类就是你要扩展的类。在这种情况下,被扩展的类被标记为sealed——一种使类可枚举的方法sealed classes

    您可以阅读有关对象here 的信息,在这种情况下,使用对象代替类,因为不需要通过这个特定的NavigationCommand 传递参数

    【讨论】:

      【解决方案2】:

      代码是用 Kotlin 语言编写的。它使用sealed 类来定义所有命令。要了解有关sealed 课程的更多信息,请使用此link

      1. 所以它所做的就是定义类NavigationCommand,然后定义从NavigationCommand 扩展的内部类To。在定义To 类期间调用NavigationCommand() 与调用超级构造函数相同。例如,Java 中 To 类的相同内容可以这样写:
      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. Kotlin 中的 object 关键字创建单例类。要了解有关 object 关键字的更多信息,请使用此 link

      【讨论】:

        【解决方案3】:

        我也读过那篇文章。 据我了解:

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

        这提供了actions 在一种情况下可以做的所有事情。 例如,您的图表有一些片段:S -> A -> B -> C -> D

        现在,您在片段C 中。 您可能想要执行以下操作之一:

        1. 我想导航到 D -> sendCommand:NavigationCommand.To(R.id.Id_Of_D)
        2. 我想导航到上一个屏幕:-> sendCommand:NavigationCommand.Back
        3. 我想导航回A -> sendCommand: NavigationCommand.BackTo(R.id.Id_Of_A)
        4. 我想导航回当前图的根:-> sendCommand:NavigationCommand.ToRoot)

        原来如此。

        您需要从视图模型发送一些命令,之后视图模型会将该事件触发到实时数据。 接下来,最重要的在这里 - How is that event is comsumed。 你得看看BaseFragment

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

        文章中有小工具。 但是对于完整的实现,它看起来像这样: 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)
                    }
                }
            }
        }
        

        所以,到目前为止,您会看到,我们在视图模型中发布到navigationCommands 的所有事件都在这里处理。

        祝你编码愉快!

        【讨论】:

        • 请记住,您永远不需要扩展 NavigationCommand。您只需通过传递正确的参数来使用它 - 方向。
        猜你喜欢
        • 2011-10-18
        • 1970-01-01
        • 2018-06-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多