无Fragment的Activity中二次获取ViewModel的最优方案
Activity中二次获取ViewModel的最佳实践
问题背景
官方推荐在Activity的onCreate方法内通过以下方式首次获取ViewModel:
public class FooActivity extends AppCompatActivity { @Inject ViewModelProvider.Factory viewModelFactory; @Override protected void onCreate(Bundle savedInstanceState) { //... FooViewModel viewModel = new ViewModelProvider(this, viewModelFactory) .get(FooViewModel.class); } }
但每次创建ViewModelProvider会有冗余开销,若需要在onCreate之外二次获取ViewModel,该如何处理?常见疑问包括:
- 将ViewModel缓存到Activity私有变量是否会导致泄漏?
- 在
onDestroy中手动将ViewModel置为null是否更安全? - 无Fragment的Activity中,二次获取关联ViewModel的推荐方式是什么?
解答
1. 缓存ViewModel到Activity成员变量不会导致泄漏
你示例中把ViewModel存在Activity私有变量的写法是安全的,不会引发内存泄漏。原因在于:
- ViewModel的生命周期由
ViewModelStore管理,当Activity因配置变化(如旋转)重建时,ViewModel会被保留;当Activity真正销毁(非配置变化场景)时,ViewModelStore会自动调用clear()方法销毁ViewModel,此时Activity对ViewModel的引用也会随之失效。 - 手动在
onDestroy中将ViewModel置为null完全是多余操作,系统已经会妥善处理ViewModel的生命周期,无需额外干预。
2. 二次获取ViewModel的推荐方式
推荐以下两种高效且安全的方案:
方案一:缓存ViewModel到Activity成员变量(最简便)
直接将ViewModel作为Activity的成员变量,在onCreate中初始化后,后续在任意生命周期方法或自定义方法中直接使用即可,无需重复获取:
public class FooActivity extends AppCompatActivity { private FooViewModel viewModel; @Inject ViewModelProvider.Factory viewModelFactory; @Override protected void onCreate(Bundle savedInstanceState) { //... viewModel = new ViewModelProvider(this, viewModelFactory) .get(FooViewModel.class); } @Override protected void onStop() { //... viewModel.someMethod(); } }
方案二:缓存ViewModelProvider实例
如果需要获取多个不同类型的ViewModel,可以缓存ViewModelProvider而非单个ViewModel,后续通过该Provider实例获取对应ViewModel,避免重复创建Provider:
public class FooActivity extends AppCompatActivity { private ViewModelProvider viewModelProvider; @Inject ViewModelProvider.Factory viewModelFactory; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //... viewModelProvider = new ViewModelProvider(this, viewModelFactory); // 首次获取FooViewModel FooViewModel fooViewModel = viewModelProvider.get(FooViewModel.class); } private void handleSomeAction() { // 二次获取FooViewModel FooViewModel fooViewModel = viewModelProvider.get(FooViewModel.class); // 获取其他类型ViewModel BarViewModel barViewModel = viewModelProvider.get(BarViewModel.class); } }
补充说明
即使你不缓存ViewModel或ViewModelProvider,每次通过new ViewModelProvider(this, viewModelFactory).get(...)获取的也是同一个ViewModel实例——因为ViewModelProvider内部会从Activity关联的ViewModelStore中查找已有实例,不存在重复创建ViewModel的问题,只是创建ViewModelProvider本身有微小的开销,所以缓存是更优选择。
内容的提问来源于stack exchange,提问作者Mister Smith
相关产品推荐
相关产品推荐

