Android导航对话框片段回调
我的项目(MVVM,Jetpack navigation)中有DialogFragment,它从不同的地方调用并表示签名画布。导航相关部分:Android导航对话框片段回调,android,mvvm,android-dialogfragment,android-jetpack,Android,Mvvm,Android Dialogfragment,Android Jetpack,我的项目(MVVM,Jetpack navigation)中有DialogFragment,它从不同的地方调用并表示签名画布。导航相关部分: <dialog android:id="@+id/signPadDialogFragment" android:name="com.ui.signpad.SignPadDialogFragment" android:label="SignPadDialogFragment" /> <f
<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>
所以,我的问题是:使用Jetpack导航和MVVM处理回调的正确方法是什么?
我看到两个可能的解决方案和相关问题:
我可以将数据从对话框片段传递到ViewModel->Repository(在本例中:如何区分在对话框范围内启动对话框的操作?)
或者在MainActivity中获得回调(如何?)
提前感谢由于
导航控制器API的限制,只能从存在android上下文的元素中发现它。这意味着您的主要选择是:
AndroidViewModel:我不推荐它,因为它很容易被这里的上下文冲昏头脑,如果您不知道自己在做什么,这将导致内存泄漏
活动:处理活动中的导航。单活动体系结构将使问题复杂化,因为您必须限制这里的所有导航逻辑
片段:处理其范围内每个片段的导航。这是更好的方法,但下面有一个更好的解决方案
ViewModel:在其作用域内的ViewModel中处理每个片段的导航。(个人偏好)
在Jetpack导航组件中使用ViewModel
从技术上讲,导航登录仍将驻留在片段中
,除非导航API
发生更改,否则无法避免,但是我们可以将主要部分委托给视图模型
,如下所示:
ViewModel将公开一个SingleLiveEvent
并在其中封装一个NavDirection
SingleLiveEvent
是一种只触发一次的实时数据,这是我们在导航时需要的。Jose Alcérreca写了一篇很棒的博客:
Fragment
将观察此SingleLiveEvent
,并将使用该导航方向执行导航事务
ViewModel公开SingleLiveEvent:
您可以使用BaseFragment
和BaseViewModels
来遵循
,但请始终记住,任何以
作为前缀的内容都会很快变成代码气味,因此请尽可能简洁
mainActivityViewModel.repository.navigationCommands.observe(this, Observer { navEvent ->
navEvent.getContentIfNotHandled()?.let {
navController.navigate(it as NavDirections)
}
})
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) }
}
})
}