Android导航对话片段回调

问题描述 投票:0回答:1

在我的项目中(MVVM, Jetpack navigation)有一个DialogFragment,它从不同的地方调用并代表签名画布。导航中的相关部分。

 <dialog
        android:id="@+id/signPadDialogFragment"
        android:name="com.ui.signpad.SignPadDialogFragment"
        android:label="SignPadDialogFragment" />

 <fragment
        android:id="@+id/loginFragment"
        android:name="com.ui.login.LoginFragment"
        android:label="@string/login_label"
        tools:layout="@layout/login_fragment">

        <action
            android:id="@+id/action_loginFragment_to_currentJobsFragment"
            app:destination="@id/currentJobsFragment" />
        <action
            android:id="@+id/action_loginFragment_to_signPadDialogFragment"
            app:destination="@id/signPadDialogFragment" />

<fragment
        android:id="@+id/jobDetailFragment"
        android:name="com.ui.jobdetails.JobDetailFragment"
        android:label="job_detail_fragment"
        tools:layout="@layout/job_detail_fragment" >
        <action
            android:id="@+id/action_jobDetailFragment_to_signPadDialogFragment"
            app:destination="@id/signPadDialogFragment" />
    </fragment>

和导航动作。

 mainActivityViewModel.repository.navigationCommands.observe(this, Observer { navEvent ->
            navEvent.getContentIfNotHandled()?.let {
                navController.navigate(it as NavDirections)
            }

        })

所以,我的问题是:使用Jetpack导航和MVVM处理回调的正确方法是什么?我看到了两种可能的解决方案和相关问题。

我可以将数据从对话框片段传给ViewModel -> Repository(和在这种情况下: 在这种情况下:如何在对话框范围内区分启动对话框的动作?)

或者在MainActivity中得到一个回调(如何?)

先谢谢你

android mvvm android-dialogfragment android-jetpack
1个回答
0
投票

由于 NavController API的元素中发现,它只能从具有android context 目前。这意味着你的首要选项是。

  1. AndroidViewModel: 我不建议这样做,因为在这里很容易被上下文冲昏头脑,如果你不知道自己在做什么,会导致内存泄漏。
  2. 活动(Activity)。在Activity中处理导航。单一的Activity架构会让事情变得复杂,因为你必须把所有的导航逻辑都压缩在这里。
  3. Fragment:处理每个片段的导航。在它的范围内处理每个片段的导航。这是更好的方式,但下面还有一个更好的解决方案。
  4. ViewModel.ViewModel:处理每个fragment的导航。在其作用域的viewModel中处理每个fragment的导航。(个人偏好)。

在Jetpack导航组件中使用ViewModel

从技术上讲,导航登录仍将驻留在 Fragment,没有人可以逃避,除非 navigation API 变化,但我们可以将主要部分委托给 ViewModel 如下所示。

  1. ViewModel将暴露一个 SingleLiveEvent 囊括 NavDirection 中。SingleLiveEvent 是一个只被触发一次的Live Data,这也是我们在导航方面所希望的。Jose Alcérreca有一篇很棒的博文。

    https:/medium.comandroiddeveloperslivedata-with-snackbar-navigation-andother-events-the-singleliveevent-case-ac2622673150。

  2. Fragment 将此 SingleLiveEvent 并将以此 NavDirection 来执行一个导航事务。

暴露SingleLiveEvent的ViewModel。

open class BaseViewModel : ViewModel() {
  /**
   * Navigation Component API allows working with NavController in the Following:
   * 1.) Fragment
   * 2.) Activity
   * 3.) View
   *
   * In order to delegate the navigation logic to a viewModel and allow fragment
   * or an activity to communicate with viewModel, we expose navigationCommands
   * as LiveData that contains Event<NavigationCommand> value.
   *
   * Event<T> is simply a wrapper class that will only expose T if it has not
   * already been accessed with the help of a Boolean flag.
   *
   * NavigationCommand is a Sealed class which creates a navigation hierarchy
   * where child classes can take NavDirections as properties. We will observe the
   * value of NavigationCommand in the fragment and pull the NavDirections there.
   */
  private val _navigationCommands = MutableLiveData<Event<NavigationCommand>>()
  val navigationCommands: LiveData<Event<NavigationCommand>>
    get() = _navigationCommands

  fun navigate(directions: NavDirections) {
    _navigationCommands.postValue(Event(NavigationCommand.To(directions)))
  }
}

从ViewModel观察这个SingleLiveEvent的片段。

  private fun setupNavigation() {
    viewModel.navigationCommands.observe(viewLifecycleOwner, Observer {
      val navigationCommand = it.getContentIfNotHandled()

      when (navigationCommand) {
        is NavigationCommand.To -> { findNavController().navigate(navigationCommand.directions) }
      }
    })
  }

你可以利用 "SingleLiveEvent: Fragment "来观察这个SingleLiveEvent。BaseFragmentBaseViewModels 遵循 DRY但要永远记住,任何事情,有 Base 作为前缀很快就会变成一种代码味,所以要尽量简洁。

© www.soinside.com 2019 - 2024. All rights reserved.