Android中的Dagger2范围和存储模式

Android中的Dagger2范围和存储模式,android,repository-pattern,dagger-2,Android,Repository Pattern,Dagger 2,我在Android中使用了Dagger 2和存储库模式,我被我应该使用哪个范围来处理存储库的依赖关系以及使用它们的权衡所绊倒 通常,我会为每个功能创建一个存储库。因此,如果我们讨论的是注册功能,那么我将创建一个注册存储库。RegistrationRepository将有3个不同的数据源:RegistrationNetworkSource、RegistrationDiscSource和RegistrationMemorySource。当我的活动向RegistrationRepository发出请求

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

通常,我会为每个功能创建一个存储库。因此,如果我们讨论的是注册功能,那么我将创建一个注册存储库。RegistrationRepository将有3个不同的数据源:RegistrationNetworkSource、RegistrationDiscSource和RegistrationMemorySource。当我的活动向RegistrationRepository发出请求时,repo将创建一个RxJava可观察对象并将其返回给活动。然后,活动可以订阅可观察到的内容并等待结果。如果活动在observable返回结果之前发生配置更改,那么observable可以缓存在一个单独的类中,该类的作用域是应用程序生命周期,并且在重新创建活动之后,它可以获取这个缓存的observable并重新订阅。这就是我困惑的开始。如果我的observable被缓存在一个范围为应用程序范围的类中,这是否意味着3个存储库数据源也需要范围为应用程序范围


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

这个问题与您的问题非常相似,但似乎存在一些未解决的疑问

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

然后,您通常会期望您获得的咖啡机实例遵循单个活动的生命周期。但是,如果您使用其中一个CoffeeMaker实例并在应用程序类中维护对它的引用,则该实例将一直存在,直到应用程序被销毁

让我们尝试将此应用于您的问题:

如果我的observable被缓存在一个范围为应用程序范围的类中,这是否意味着3个存储库数据源也需要范围为应用程序范围

不,存储库数据源可以在@PerActivity范围内,您可以在@PerApplication@Singleton范围内维护对可观察对象的引用。其他匕首2的答案在这里已经谈到了使用持有人模式为这一点。简言之,您将创建一个单例类,该类能够在应用程序范围级别存储观测结果。当您使用RegistrationNetworkSource发出请求时,您可以使持有者订阅、接收和缓存结果。您的活动可以从持有者那里获得待定结果,而不是直接从RegistrationRepository订阅可观察结果

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

您需要多长时间的长时间运行的网络请求才能经受住配置更改?考虑使用类似的< /P> Dagger 2和Rx Java Observable不是更适合您的用例吗?请注意装载机文档中的以下内容:

加载器在配置更改期间保持并缓存结果,以防止重复查询


如果我的每个数据源的作用域都是活动,并且我在活动中创建了一个可观察对象,然后将其缓存,然后活动经历了配置更改,那么缓存的可观察对象将具有对原始数据源的引用。创建新活动时,它将获得数据源的全新实例。如果我从缓存中获取旧的可观测数据并重新订阅,那么可观测数据将在旧数据源上运行,一旦该操作完成,这些旧数据源将超出范围并符合垃圾收集的条件,对吗?继续,然后在重新创建的活动中,如果我启动创建旧可观测数据的相同事件,创建的新可观察对象现在将使用新创建的数据源进行操作。因此,我所要求的是可能的,但如果在长时间运行期间发生配置更改,将占用比所需更多的内存
操作,因为原始可观察对象将引用旧数据源,并且在重新创建活动后,它将创建新的数据源,因此在一段时间内,在原始操作完成之前,我将在内存中保留旧数据源和新数据源。@neonDion听起来不错,我认为当您的两个实例数据源处于活动状态将是一个问题,因为它只会在请求期间发生配置更改的情况下发生。您最初提出的方法是在应用程序运行时将所有数据源都存储在内存中。顺便说一句,你确定你不想使用加载器甚至服务吗?服务和加载器是潜在的解决方案,但是这些网络调用通常不会长时间运行,但最好假设它们可以长时间运行,以便活动可以进行配置。在调用过程中进行更改,因此使用适用于应用程序生命周期的网络层就足够了。在内存中保留旧数据源并创建新数据源的内存占用并不一定是禁止的,但是我认为这是一个重要的区别。如果您使用的是内存源,并且该活动经历了配置更改,那么下次尝试使用内存源时,它将是一个新实例,并且可能是空的,因此内存中可能重要的内容将不再存在。出于这个原因,最好将数据源的范围限定到应用程序,并根据需要取消对它们的引用。
@Provides
@PerActivity
public CoffeeMaker coffeeMaker(HotWater hotWater, Beans beans) {
    return new DefaultCoffeeMaker(hotWater, beans);
}