我的项目(MVVM,Jetpack导航)中有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->存储库(在这种情况下:如何区别在对话框作用域内启动对话框的操作?)
或者在MainActivity中获得回调(如何?)
预先感谢
答案 0 :(得分:0)
由于 NavController API
的局限性,因此只能从存在Android context
的元素中发现。这意味着您的主要选择是:
从技术上讲,导航登录名仍将保留在 Fragment
中,除非navigation API
进行了更改,否则无法逃避,但是我们可以将主要部分委托给 {{1 }} 如下:
ViewModel将显示一个 ViewModel
,其中包含一个 SingleLiveEvent
。 NavDirection
是仅触发一次的实时数据,这是我们在导航时需要的。何塞·阿尔塞雷卡(JoseAlcérreca)撰写了一篇很棒的博客文章:
SingleLiveEvent
将遵守此 Fragment
并将使用该 SingleLiveEvent
进行导航交易。
NavDirection
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)))
}
}
您可以使用 private fun setupNavigation() {
viewModel.navigationCommands.observe(viewLifecycleOwner, Observer {
val navigationCommand = it.getContentIfNotHandled()
when (navigationCommand) {
is NavigationCommand.To -> { findNavController().navigate(navigationCommand.directions) }
}
})
}
和 BaseFragment
来跟踪 BaseViewModels
,但始终可以请记住,任何以 DRY
作为前缀的东西都会很快变成代码的味道,因此请保持简洁。