Android 中的 Dagger 2 范围和存储库模式

Dagger2 scopes and RepositoryPattern in Android

我在 Android 中使用 Dagger 2 和 Repository 模式,我被我应该使用哪个范围来存储库的依赖关系和使用它们的权衡所绊倒。

通常我会为每个功能创建一个存储库。因此,如果我们谈论注册功能,那么我会创建一个 RegistrationRepository。 RegistrationRepository 将有 3 个不同的数据源,RegistrationNetworkSource、RegistrationDiscSource 和 RegistrationMemorySource。当我的 Activity 向 RegistrationRepository 发出请求时,repo 将创建一个 RxJava observable 并 return 它到 activity。然后 activity 可以订阅可观察对象并等待结果。如果 activity 碰巧在可观察对象 return 产生结果之前经历了配置更改,那么可观察对象可以缓存在一个单独的 class 中,该范围限定为应用程序生命周期并在 activity 被重新创建,它可以获取这个缓存的可观察对象并重新订阅它。这就是我的困惑开始的地方。如果我的 observable 被缓存在应用程序范围内的 class 中,这是否意味着 3 个存储库数据源也需要被限定在应用程序范围内?

我的直觉告诉我,我应该将它们限定在应用程序范围内。这样做将允许每个源执行一个很长的 运行 数据获取任务,即使请求来自的 Activity 经历了配置更改,该任务也可以继续。每个应用程序都有一个实例,并且它们始终可供使用。听起来不错,但这不是浪费资源吗?如果注册是我的应用程序的第一个屏幕,用户将其余时间花在主页Activity 或其他地方,那么为什么 3 个注册数据源仍然有效?

这个问题和你的很相似,但似乎还有一些悬而未决的问题。

首先,我建议您阅读 的答案中有关范围如何工作的内容。总而言之,作用域并没有什么神奇之处,它们只是帮助您推断从组件创建的对象的生命周期。您从组件生成的依赖项的实例将存在于您维护对它们的引用的位置。通常,您会在单个 activity 中维护对从 @PerActivity 组件注入的依赖项的引用。例如,如果您的 @PerActivity CoffeeComponentCoffeeModule:

@Provides
@PerActivity
public CoffeeMaker coffeeMaker(HotWater hotWater, Beans beans) {
    return new DefaultCoffeeMaker(hotWater, beans);
}

那么您通常会期望获得的 CoffeeMaker 实例遵循单个 Activity 的生命周期。但是,如果您采用其中一个 CoffeeMaker 实例并在 Application class 中维护对它的引用,则该实例将一直存在,直到应用程序被销毁。

让我们尝试将其应用到您的问题中:

If my observable is being cached in a class that is scoped to the application scope does that mean that the 3 repository data sources also need to be scoped to the application scope?

不,存储库数据源可以限定 @PerActivity 范围并且您 可以@PerApplication 处维护对 Observables 的引用(@Singleton) 范围。这里的其他 Dagger 2 答案已经谈到了为此使用 Holder 模式。简而言之,您将制作一个单例 class,能够在应用范围级别存储 Observables 的结果。当您使用 RegistrationNetworkSource 发出请求时,您可以使 Holder 订阅、接收和缓存结果。您的 Activity 可以从 Holder 获取待定结果,而不是直接从 RegistrationRepository.

订阅 Observable

其他一些需要考虑的问题:

您需要多长时间的 运行 网络请求才能在配置更改后继续存在? 考虑使用类似 DownloadManager

的东西

Loaders 是否比 Dagger 2 和 Rx-Java Observables 更适合您的用例? Loaders 文档中的注释如下:

Loaders persist and cache results across configuration changes to prevent duplicate queries.