我有一个多模块架构,有多个功能模块,看起来像这样:
我有多个依赖于:core_library
库模块的功能模块,其中包含所有常见的依赖项(Retrofit、Room等),然后是针对每个不同应用流程的不同功能模块,最后是:app
应用模块。
如果您想在功能模块中互不了解的Activity之间导航,我使用AppNavigator
接口:
interface AppNavigator {
fun provideActivityFromFeatureModuleA(context: Context): Intent
}
然后在:app
模块Application
类中实现这个接口,由于:app
模块把所有东西都联系在一起,所以它知道每个特性模块中的每个活动:
class MyApp : Application(), AppNavigator {
...
override fun provideActivityFromFeatureModuleA(context: Context): Intent {
return Intent(context, ActivityFromA::class.java)
}
...
}
此AppNavigator
组件位于:core_library
中的Dagger模块中,并且可以注入到任何特性模块中。
我有这个:feature_login
功能模块,当用户创建一个新帐户,必须通过入站流程,如邀请朋友加入应用程序,检查POST_NOTIFICATION
权限,添加任何更多的细节到其帐户,等等。
每个:feature_modules
都有一个Activity
和许多Fragments
我有一个导航图来在片段之间导航。
- 问题是**
:feature_login
导航图看起来像这样:
问题是,我需要在应用程序的不同部分重用这些片段中的许多片段,更具体地说,这些片段
例如:当我打开应用程序并进入主屏幕时,我会检查POST_NOTIFICATION
权限,如果这些权限尚未被授予,我想提示PostNotificationFragment
检查并向用户显示UI。如果用户想从"设置"屏幕更改它们,则应提示SelectSquadronFragment
+ SelectNumberFragment
。在执行某些操作时,我希望使用InviteFriendsFragment
提示用户。
- 问题是我不知道如何独立地重用这些片段,而不让它们在流的其余部分中导航 *
"我所尝试的"
- 子图并不能真正解决这个问题。我可以使用
AppNavigator
来提供我在:feature_login
中的托管Activity或每个单独的Fragment,但问题仍然存在。如果用户从Settings打开SelectSquadronFragment
+SelectNumberFragment
,我不希望用户之后必须通过FinishFragment
。 - 提取通过接口到Activity的导航。该导航图中的每个Fragment都通过
NavDirections
导航。当我想从MedictFragment
导航到InviteFriendsFragment
时,我使用MedicFragmentDirections
。我在考虑让Activity
提供这些NavDirections
,这样我就可以创建具有所需导航路线的自定义Activity。但老实说,我更喜欢一些不那么高深的东西。
请让我知道,如果你需要我给你更多的信息。任何反馈是受欢迎的。
- 示例**
让我给你们一个精确的例子来说明我在这里遇到的困难,让我们使用一些简单的东西,让我们以ChooseRoleFragment
为例。ChooseRoleFragment
是一个简单的UI,在***登录流程***中显示了三个按钮和三个角色("警察"、"医生"和"消防员"),当用户点击这三个按钮中的一个时,他将被带到PoliceFragment
、FiremanFragment
或MedicFragment
。这是在*登录流程中。
现在,我需要在应用程序的"设置"部分重新使用这个ChooseRoleFragment
。唯一的区别是,当我在那里使用它时,我不希望它导航到FiremanFragment
、MedicFragment
或PoliceFragment
,我只想让它回到"设置"屏幕。"设置"屏幕在一个完全不同的功能模块上,不"我对:feature_login
一无所知
更清楚地说,ChooseRoleFragment
通过导航图导航到PoliceFragment
、FiremanFragment
或MedicFragment
,这意味着在ChooseRoleFragment
中,当我单击每个选项时,我会看到如下内容:
class ChooseRoleFragment : Fragment() {
//...
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
bindings.policeBtn.setOnClickListener {
findNavController().navigate(ChooseRoleFragmentDirections.actionChooseRoleFragmentToPoliceFragment())
}
bindings.medicBtn.setOnClickListener {
findNavController().navigate(ChooseRoleFragmentDirections.actionChooseRoleFragmentToMedicFragment())
}
bindings.firemanBtn.setOnClickListener {
findNavController().navigate(ChooseRoleFragmentDirections.actionChooseRoleFragmentToFiremanFragment())
}
}
}
所以,这对于登录流程非常有效,但是对于"Settings"屏幕,它不能完成我想要的功能。所以我想弄清楚的是,我应该在某个地方提取这些NavDirections
吗?这样,当我想在"Settings"屏幕中重用这个Fragment时,我可以覆盖NavDirections
,让它导航到其他地方。
1条答案
按热度按时间1tu0hz3e1#
您的目标是将不同的接口实现传递到ViewModel的构造函数中,以便当Fragment访问时,它会更改您要访问的目的地。您还希望提取这些来自外部的调用
findNavController().navigate(ChooseRoleFragmentDirections.actionChooseRoleFragmentToPoliceFragment())
,而不是直接硬编码操作必须执行的操作。此外,如果这些Fragment被重用,它们不能拥有自己的操作。这些动作必须来自其封闭的NavGraph。那么,如何根据当前的应用程序状态将不同的接口实现放入Fragment或ViewModel中呢?
问得好,因为ViewModel(它将
<T extends ViewModel>
硬编码为预期类型)和Hilt(全局配置)都不是为此设计的。如果你坚持使用Jetpack Navigation,我可以设想两种选择(你就是这样,因为你的应用很大):1.)在Fragment中定义一个接口为“ActionHandler”,并期望
ActionHandler
实现的FQN作为fragment参数,然后使用Class.forName(FQN).newInstance()
获取对它的引用,这将定义Fragment必须执行的导航动作。2.a)在ViewModel中定义接口为“ActionHandler”,并期望
ActionHandler
作为构造函数参数。根据当前可用的NavGraph,从定制ViewModelProvider.Factory
(可能是initializerViewModel {
)传入不同的ActionHandler
实现。然而,这需要在您的定制ViewModelProvider.Factory
中看到NavController。2.b)合并这两种思想
initializerViewModel {
接收CreationExtras
,包括关联的SavedStateHandle
,因此您可以通过SavedStateHandle
将类似“mode”的枚举(或之前的FQN)接收到ViewModelProvider.Factory
中,并基于片段参数设置ActionHandler
实现的条件。这样,您可以为
ActionHandler
创建工厂,而不必在Fragment类中硬编码操作处理。如果您使用FQN,请确保使用@Keep
注解或相关的Proguard规则来@Keep
该类。此ActionHandler
实现需要查看多个NavGraph,所以它基本上是:app
中定义的某种Navigator
,或者至少是一个可以看到多个NavGraph的模块。