的范围限定为对象A到对象B,这意味着对象B在其整个生命周期中始终持有A的同一个实例。当谈到DI(依赖注入)时,将对象A限定在容器中意味着容器始终提供相同的A实例,直到它被销毁。在Hilt中,您可以使用注解将类型的范围限制在特定的容器或组件中。例如,您的应用程序有一个处理登录和注销的UserManager类型。您可以使用@Singleton批注将类型范围限定为ApplicationComponent(ApplicationComponent是一个在整个应用程序生命周期内进行管理的容器)。作用域类型在应用程序组件内向下传递到组件层次结构:在这种情况下,相同的UserManager实例将提供给层次结构内的其余Hilt组件。应用程序中依赖于UserManager的任何类型都将获得相同的实例。组件层次结构https://developer.android.google.cn/training/dependency-injection/hilt-android#component-hierarchy注意:默认情况下,Hilt中的绑定没有作用域。这些绑定不属于任何组件,并且在整个项目中都可以访问。每次请求时都会提供此类型的不同实例。当您将绑定范围限定为组件时,它会限制您可以使用该绑定的位置以及该类型可以具有的依赖项。在Android中,您还可以在不使用DI库的情况下通过AndroidFramework手动范围。让我们看看如何手动确定范围以及如何改用Hilt确定范围。最后,我们将比较使用AndroidFramework手动确定范围与使用Hilt确定范围。Android中的作用域查看上面的定义,您可能会反对在特定类中使用类型的实例变量也可以作用域变量类型。这是正确的!当不使用DI时,你可以这样做:变量是同一个实例。如果另一个类由于某种原因需要访问这个作用域变量,它每次都会获得相同的实例。当创建一个新的MyActivity实例时(例如系统设置更改),将创建一个新的AnalyticsAdapter实例。使用Hilt,等效代码如下:@ActivityScopedclassAnalyticsAdapter@Injectconstructor(){...}@AndroidEntryPointclassExampleActivity:AppCompatActivity(){@InjectlateinitvaranalyticsAdapter:AnalyticsAdapter}每次创建MyActivity时,它都会持有ActivityComponentDI容器的新实例.在销毁之前,此实例将向组件层次结构中的依赖项提供相同的AnalyticsAdapter实例。ComponentHierarchyhttps://developer.android.google.cn/training/dependency-injection/hilt-android#component-hierarchy更改系统设置后,您将获得一个由ViewModel作用域的AnalyticsAdapter和MainActivity的新实例但是,我们可能希望AnalyticsAdapter在系统设置更改后继续存在!或者,我们希望在用户离开Activity之前将实例限定在Activity范围内。为此,您可以使用ComponentArchitecture中的ViewModel,因为它在系统设置更改后仍然存在。组件架构中的ViewModelhttps://developer.android.google.cn/topic/libraries/architecture/viewmodel当不使用依赖注入时,你可能有如下代码:classAnalyticsAdapter(){...}classExampleViewModel():ViewModel(){valanalyticsAdapter=AnalyticsAdapter()}classExampleActivity:AppCompatActivity(){privatevalviewModel:ExampleViewModelbyviewModels()privatevalanalyticsAdapter=viewModel.analyticsAdapter}这样您就可以将AnalyticsAdapter的范围限定到ViewModel。因为Activity可以访问ViewModel,所以相同的AnalyticsAdapter实例在该Activity中始终可用。通过使用Hilt,您可以通过将AnalyticsAdapter的范围限定到ActivityRetainedComponent来实现相同的行为,因为ActivityRetainedComponent还可以在系统设置更改时保持不变。@ActivityRetainedScopedclassAnalyticsAdapter@Injectconstructor(){...}@AndroidEntryPointclassExampleActivity:AppCompatActivity(){@InjectlateinitvaranalyticsAdapter:AnalyticsAdapter}通过在ViewModel或Hilt中使用ActivityRetainedScope注解,如果你想在系统设置改变后得到相同的实例,如果你想遵循良好的While保持在保持DI实践的同时处理视图逻辑的ViewModel,您可以使用@ViewModelInject提供ViewModel依赖项。关于该注解的详细说明,请参考:文档|使用Hilt注入ViewModel对象。这样,AnalyticsAdapter就不需要限定在ActivityRetainedComponent范围内,因为此时它被手动限定在ViewModel范围内:Documentation|使用Hilt注入ViewModel对象https://developer.android.google.cn/training/dependency-injection/hilt-jetpack#viewmodelsclassAnalyticsAdapter@Injectconstructor(){...}classExampleViewModel@ViewModelInjectconstructor(privatevalanalyticsAdapter:AnalyticsAdapter):ViewModel(){...}@AndroidEntryPointclassExampleActivity:AppCompatModelActivity(){privatevalviewModel:ExampleViewModelbyAdvalanalyticsViewModels()analyticsAdapter}我们刚才看到的可以应用于由Android框架生命周期类管理的任何Hilt组件。单击以查看所有可用范围。回到我们最初的例子,当不使用DI框架时,对ApplicationComponent的作用域相当于将实例保留在Application类中。Allavailablescopeshttps://developer.android.google.cn/training/dependency-injection/hilt-android#component-scopes与Hilt和ViewModellimitedscopes相比使用Hiltlimitedscopes的好处是可以使用HiltcomponentlevelsStructs使用作用域类型;对于ViewModel,必须通过ViewModel手动访问范围类型。确定ViewModel范围的优点是您可以将ViewModel保存在应用程序中的任何LifecyclerOwner对象中。例如,如果您使用JetpackNavigation库,则可以将ViewModel绑定到NavGraph。LifecyclerOwnerhttps://developer.android.google.cn/reference/androidx/lifecycle/LifecycleOwnerJetpack导航库https://developer.android.google.cn/guide/navigation/navigation-getting-startedNavGraphhttps://developer.android.google.com/reference/androidx/navigation/fragment/NavHostFragmentHilt提供了有限数量的范围。可能没有与您的特定使用场景相匹配的范围。例如嵌套片段,对于这种情况,您可以退后一步并使用ViewModel范围。使用Hilt注入ViewModel如上所述,您可以使用@ViewModelInject将依赖项注入ViewModel。这个想法是这些绑定保存在ActivityRetainedComponent中,这就是为什么您只能注入无作用域类型或作用域为ActivityRetainedComponent和ApplicationComponent的类型。如果Activity或Fragment被@AndroidEntryPoint注解修饰,则可以通过getDefaultViewModelProviderFactory()方法获取Hilt生成的ViewModel工厂。由于这些ViewModel工厂可以在ViewModelProvider中使用,因此您获取ViewModel的方式变得更加灵活。例如:ViewModel作用域为BackStackEntry。作用域是有代价的,因为提供的对象将保留在内存中,直到持有者被销毁。请仔细考虑在您的应用程序中使用作用域对象。如果对象的内部状态需要使用相同的实例,如果对象需要同步,或者如果对象的创建成本很高,则范围界定是合适的。当然,当你需要限定作用域时,可以使用Hilt中的作用域注解,也可以直接使用AndroidFramework。
