Jetpack Compose中SharedViewModel的两种注入方式哪种更优?
问题
我需要使用Navigation,同时要求每个页面都能使用SharedViewModel的实例。以下是我的尝试:
class MainActivity : ComponentActivity() { private lateinit var navController: NavHostController private val viewModel: SharedViewModel by viewModels() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { navController = rememberNavController() NavGraph( navController = navController, sharedViewModel = sharedViewModel ) } } }
如你所见,我将navController和sharedViewModel传递给了NavGraph。
fun NavGraph( navController: NavHostController, sharedViewModel: SharedViewModel ) { NavHost( navController = navController, startDestination = HomeScreen.route ) { composable( route = HomeScreen.route ) { HomeScreen( sharedViewModel = sharedViewModel ) } composable( route = ProfileScreen.route ) { ProfileScreen( sharedViewModel = sharedViewModel ) } } }
为了在每个页面中使用SharedViewModel,我将实例传递给每个Composable函数,这种方式运行正常。不过我了解到可以直接在每个Composable中注入ViewModel实例,代码如下:
fun HomeScreen( viewModel: SharedViewModel = hiltViewModel() ) { //... }
哪种方式更好?是像第一种方式那样将SharedViewModel实例传递给所有Composable函数,还是像第二种方式那样直接注入?
回答
两种方式各有优劣,具体选哪种得看你的项目场景,咱们从几个核心维度拆解:
耦合性与维护成本
- 手动传参:每个页面Composable都得显式接收
SharedViewModel参数,相当于把ViewModel和页面硬绑在一起了。哪天要换ViewModel的类型或者调整创建逻辑,所有传参的地方都得改,维护起来麻烦。而且页面得知道ViewModel的来源,不符合依赖注入的解耦思路。 - Hilt注入:用
hiltViewModel()自动注入,页面只需要声明“我需要这个ViewModel”,不用管它是怎么来的。后续改ViewModel实现,页面代码完全不用动,耦合度低很多,也更符合单一职责。
生命周期控制
- 手动传参:你在
MainActivity里创建的ViewModel,生命周期和Activity绑定。只要Activity活着,ViewModel就不会销毁,跨页面共享确实能实现,但如果你的导航组件是嵌套在Fragment里,这种方式可能让ViewModel活得太长,占内存。 - Hilt注入:默认情况下
hiltViewModel()会绑定到NavHost的宿主组件(比如Activity或Fragment)的生命周期,还能通过hiltViewModel(navController.getBackStackEntry(R.id.your_nav_graph))绑定到特定导航图的生命周期,想让ViewModel在导航图销毁时跟着销毁也能做到,更灵活,能避免不必要的内存占用。
测试难度
- 手动传参:写单元测试时直接传个Mock的ViewModel就行,不用搞Hilt的测试配置,上手快,适合小项目快速测试。
- Hilt注入:虽然Hilt有测试模块可以替换依赖,但得额外配置测试组件,步骤比手动传参多。不过大型项目里,这种依赖注入的方式扩展性更好,统一管理依赖更省心。
代码简洁度
- 手动传参:NavGraph要传,每个页面也要接,页面多了的话重复代码一堆,看着乱糟糟的。
- Hilt注入:每个页面只需要加个默认参数
viewModel: SharedViewModel = hiltViewModel()就行,不用到处传,代码清爽很多。
总结
如果你的项目已经用了Hilt,优先选注入方式,解耦、好维护、生命周期控制灵活,适合中大型项目长期迭代。
要是项目很小,或者你就想测试简单点,手动传参也能用,但得注意ViewModel的生命周期,别搞出内存泄漏。
内容的提问来源于stack exchange,提问作者Always Learner
相关产品推荐
相关产品推荐

