使用Hilt注入ViewModel时init代码块未触发的原因排查
问题根因
init块不触发,核心是没搞懂by viewModels()委托的实际工作逻辑,具体问题如下:
by viewModels()本身是惰性加载的代理实现。你写的private val mainViewModel : MainViewModel by viewModels()这行声明,只是生成了一个存放ViewModel获取逻辑的代理对象,根本不会立刻创建MainViewModel实例。只有当代码第一次实际访问mainViewModel这个属性——比如读它的值、调它的公开方法——的时候,系统才会从当前Activity的ViewModelStore里找现成的实例,或者构造新的实例,这时候才会走类的构造流程、执行init块的代码。- 你现在的MainActivity从声明mainViewModel到onCreate走完,全程没碰过这个变量,ViewModel自然不会被创建,init块根本没机会跑。你要是在onCreate里随便加一句比如
Log.d("test", mainViewModel.toString()),马上就能看到init里的日志打出来。
这部分和Hilt完全没关系,哪怕不用Hilt,用原生的by viewModels(),惰性加载的规则都是一样的。Hilt只是帮你自动把ViewModel依赖的MainRepo构造好,不会改动委托本身的初始化时机。
可行的修正方式
- 如果要在Activity启动时就发对应API请求,别靠init块的隐式触发,优先选可控性更高的方案:
- 把原来写在init块里的请求逻辑,封装成ViewModel的公开方法,比如
fun loadAlbumList(),在MainActivity的onCreate里访问到mainViewModel实例后,主动调用这个方法,逻辑触发时机完全由自己掌控,不会被惰性加载的规则坑到。 - 要是实在想保留init自动执行的写法,就在onCreate里主动访问一次mainViewModel的属性,比如把它绑定到DataBinding的viewModel字段、或者打印个实例日志,把代理的实例化流程唤醒。
小的优化提醒
你现在init块里写的协程请求没有做任何异常捕获,后续接口请求出错的时候,错误会直接冒泡到viewModelScope的协程上下文里,建议给请求逻辑加统一的异常拦截,避免接口静默失败。
内容的提问来源于stack exchange,提问作者Yunis Rasulzade
相关产品推荐
相关产品推荐

