使用Hilt实现Jetpack Navigation下两Fragment限定生命周期共享ViewModel
方案一:官方Hilt Navigation扩展实现(推荐,无需自定义Scope)
该方案利用导航图嵌套结构的生命周期自动管理ViewModel作用域,无需手动维护自定义Scope,适配性和稳定性更高。
步骤1:添加依赖
确保模块级build.gradle中引入Hilt与Navigation的集成依赖:
dependencies { implementation "androidx.hilt:hilt-navigation-fragment:1.2.0" // 需提前引入Jetpack Navigation、Hilt核心基础依赖 }
步骤2:配置嵌套导航图
将Fragment B、Fragment C归入同一个嵌套导航图,该子图的生命周期将与ViewModel B完全对齐:
<!-- 主导航图nav_graph_main.xml --> <navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/nav_graph_main" app:startDestination="@id/fragmentA"> <fragment android:id="@+id/fragmentA" android:name="com.yourpackage.FragmentA" /> <!-- 嵌套子图:覆盖B到C的完整流程,生命周期从进入B开始,到退回A时销毁 --> <navigation android:id="@+id/nav_graph_b_flow" app:startDestination="@id/fragmentB"> <fragment android:id="@+id/fragmentB" android:name="com.yourpackage.FragmentB" /> <fragment android:id="@+id/fragmentC" android:name="com.yourpackage.FragmentC" /> </navigation> </navigation>
步骤3:定义ViewModel B
正常使用Hilt的ViewModel注解即可,无需额外配置作用域:
@HiltViewModel class ViewModelB @Inject constructor() : ViewModel() { // 此处编写业务逻辑 }
步骤4:Fragment中获取共享ViewModel
在Fragment B和Fragment C中,通过navGraphViewModels指定嵌套子图的ID,即可获取同一实例:
// Fragment B代码 @AndroidEntryPoint class FragmentB : Fragment() { private val viewModelB: ViewModelB by navGraphViewModels(R.id.nav_graph_b_flow) { defaultViewModelProviderFactory } } // Fragment C代码,实现完全一致 @AndroidEntryPoint class FragmentC : Fragment() { private val viewModelB: ViewModelB by navGraphViewModels(R.id.nav_graph_b_flow) { defaultViewModelProviderFactory } }
该实现下,ViewModel B会在用户第一次进入Fragment B时创建,在用户从Fragment B回退到Fragment A、嵌套子图完全出栈时自动销毁,完全匹配需求。
方案二:自定义Hilt Scope实现
如果需要更灵活的作用域控制,可通过自定义Hilt Scope实现,该方案需要手动管理作用域生命周期。
步骤1:定义自定义作用域注解
@Scope @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class BFlowScope
步骤2:定义作用域对应的Hilt Component
@BFlowScope @DefineComponent(parent = ActivityComponent::class) interface BFlowComponent { @DefineComponent.Builder interface Builder { fun build(): BFlowComponent } }
步骤3:定义EntryPoint提供Component构造入口
@EntryPoint @InstallIn(SingletonComponent::class) interface BFlowComponentEntryPoint { fun bFlowComponentBuilder(): BFlowComponent.Builder }
步骤4:给ViewModel B标注自定义作用域
@BFlowScope class ViewModelB @Inject constructor() : ViewModel() { // 业务逻辑 }
步骤5:管理Component生命周期
在Fragment B的onCreate方法中初始化Component,监听导航回退事件,当嵌套子图完全出栈时手动销毁Component实例,避免内存泄漏。
内容的提问来源于stack exchange,提问作者PhongBM
相关产品推荐
相关产品推荐

