获取ViewModel的Coroutine scope与Hilt
假设,我的构造函数中有一些用户酶的ViewModel类。另一方面,该用途酶在其构造函数中具有CoroutinesCope。我想将ViewModelScope用作参数。我可以用刀柄做吗?
@InstallIn(ViewModelComponent::class)
abstract class ViewModelModule {
@Provides
fun provideUseCase(scope: CoroutineScope) = MyUseCase(scope)
}
...
@HiltViewModel
class MyViewMode(useCase: MyUseCase): ViewModel() {
...
}
据我了解, viewModelComponent
仅具有 SavedStateHandle
作为默认绑定,甚至不是ViewModel本身。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果您的用户酶取决于视频酶的视图范围的范围,则您具有依赖关系循环,并且无法使用HILT解决它。
最好是向用户酶传递提供商,并在ViewModel中初始化它,或者更好,或者更好,而不是依赖CoroutinesCope,而是使您的Usecase Interface
suppend
您可以使用ktx扩展名来进行ktx扩展。生命周期感知组件,并使用
ViewModelsCope
扩展。请参阅在这里。If your UseCase depends on the scope of the ViewModel that consequently depends on the UseCase, you have a dependency loop and you can't resolve it using Hilt.
You'd be better off passing down a provider for the UseCase, and initializing it inside the ViewModel, or better yet, not depend on the CoroutineScope and instead make your UseCase interface
suspend
You can use KTX extensions for lifecycle-aware components, and use the
viewModelScope
extension. See here.另一个解决方案是使用Hilt/Dagger的辅助注射功能。此方法涉及为您的
myusecase
创建工厂,该工厂允许您根据需要传递coroutinescope
。您的工厂设置可能看起来像这样:然后,通过辅助注入更新您的
myusecase
以接受CoroutinesCope
。这仅意味着将其与您拥有的任何其他依赖关系一起添加到构造函数中。您可以做到这一点:最后,在您的
myViewModel
中,您只需要注入此工厂并使用它来实例化myusecase
,然后传递view> viewmodelscope < /代码>。您的ViewModel中的代码看起来像这样:
就是这样!通过使用辅助注入,您可以灵活地在运行时注入对象,例如
viewModelsope
。Another solution would be to use the Assisted Injection feature of Hilt/Dagger. This method involves creating a factory for your
MyUseCase
, which allows you to pass theCoroutineScope
as needed. Your factory setup might look like this:Then, update your
MyUseCase
to accept theCoroutineScope
through assisted injection. This simply means adding it to your constructor, alongside any other dependencies you have. Here's how you might do it:Lastly, in your
MyViewModel
, you just need to inject this factory and use it to instantiate yourMyUseCase
, passing in theviewModelScope
. The code in your ViewModel would look something like this:And that's it! By using Assisted Injection, you have the flexibility to inject objects at runtime such as
viewModelSope
.有趣的是,我在工作中遇到了完全相同的问题。而且我找到了至少三个解决方案。
viewModelScope
的主要问题之一是,仅在VM构造器完成后才初始化。但是它可以在init {}
block的执行时可用。我的主要解决方案是:
在Usecase中具有用于Coroutine范围的属性,然后在VM的
init {}
Block block nistionview> viewmodelscope
tousecase中。 CoroutinesCope
属性。或具有将USECase范围初始化为ViewModel的方法。只需确保在分配之前不与其范围相互作用。在ViewModel的构造函数中注入USECase所需的所有内容,在ViewModel中具有
私有Val Usecase
属性。然后在ViewModel的INIT {}
块中构造用户当USECase,传递给Uustecase的构造函数,即注入的对象以及ViewModelScope。我最终使用了此选项。有一个单独的DI模块(我正在使用刀柄,因此在刀柄的术语中进行解释),应用
@installin(viewModelComponent :: class
)与模块,然后创建@提供
在那里的coroutinescope,将@viewModelsCoped
注释对方法。然后将该范围注入@Inject
中的Usecase构造函数。从模块中提供USECASE,该模块也安装在viewModelComponent
中,并范围用Usecase@provides
@viewmodelscoped ,然后@inject
它进入ViewModel。这样,您本质上将拥有与ViewModelScope等效的CoroutinesCope。您可能还需要在此范围中添加一个限定符,以将其与其他视图模型的范围区分开(使用@qualifier或@Named)。通常可以使用这种方法来创建一个任意数量的CoroutinesCope,甚至可以将其范围用于任何生命周期,即使是应用程序。还有其他选项,例如将
viewModelScope
作为对用户酶方法的参数,或者使用USECase方法是CoroutinesCope的扩展(Fun coroutinescope.yourmethod(){}
)或仅将用户酶中的所有方法标记为暂停
并从ViewModel启动它们。如果我在某个地方错误,请随时纠正我。
Interestingly, I've come to the exact same problem in my work. And I've found at least three solutions.
One of the main problems with
viewModelScope
is that it is only initialized after the VM constructor has finished. But it is available at the time of theinit{}
block 's execution.My main solutions are:
Have a property in the useCase for a coroutine scope, then in the VM's
init{}
block assignviewModelScope
to theuseCase.coroutineScope
property. Or have a method that would initialize usecase's scope to the viewModel one. Just make sure that the useCase does not interact with its scope before it is assigned.Inject everything that the useCase needs in the viewModel's constructor, have a
private val useCase
property in the viewmodel. then construct the usecase inside the viewModel'sinit{}
block, passing to useCase's constructor the injected objects plus the viewModelScope. I have ended up using this option.Have a separate DI module (I am using Hilt, so am explaining in the Hilt's terms), apply
@InstallIn(ViewModelComponent::class
) to the module, then create a@Provides
method for a CoroutineScope there, apply the@ViewModelScoped
annotation to the method. Then have that scope injected in the UseCase's constructor with@Inject
. Provide the UseCase from a module which is also installed in aViewModelComponent
and scope the UseCase@Provides
method with@ViewModelScoped
as well ,then@Inject
it into the ViewModel. This way you will essentially have a CoroutineScope equivalent to the viewModelScope. You might also want to add a qualifier to such scope to distinguish it from the ones for other viewmodels, if needed (use @Qualifier or @Named). This approach could be used in general to create an arbitrary amount of CoroutineScope's that can be scoped to any lifecycle, even to the application.There are other options, like passing
viewModelScope
as an argument to the methods of UseCase, or having methods of UseCase be an extension of CoroutineScope (fun CoroutineScope.yourMethod(){}
) or just marking all the methods in the UseCase assuspend
and launching them from the viewModel.Feel free to correct me if I am mistaken somewhere.