39

我看过几篇不同的文章,这些文章似乎暗示了在 Dagger 2 中进行自定义范围界定的两种不同方法:

  1. 在配置更改中幸存的 MVP 演示者第 2 部分Github 存储库):

    • 为每个片段使用唯一的自定义范围,例如@Hello1Scope@Hello2ScopeforHello1FragmentHello2Fragment分别
  2. 在 Android 上品尝 Dagger 2

    • 对所有片段使用单个自定义范围,例如@PerFragment.

据我了解,似乎与方法 2 一样,定义一个可用于所有片段(即@PerFragment)的范围应该没问题。事实上(如果我错了,请纠正我),似乎自定义范围的名称无关紧要,只有创建子组件的位置(即在应用程序、活动或片段中)才重要。

是否有任何用例可以为每个片段定义唯一范围,例如案例 1?

4

2 回答 2

93

在阅读了@vaughandroid 的答案后,什么决定了 Dagger 2 中组件(对象图)的生命周期?我认为我对自定义范围的了解足以回答我自己的问题。

首先,在处理 dagger2 中的组件、模块和作用域注释时,这里有一些规则。

  • 一个组件 必须有一个(单一的)范围注释(例如@Singletonor @CustomScope)。
  • 模块 没有范围注释
  • 一个模块方法 可能有一个(单个)范围与它的组件匹配或没有范围,其中:
    • Scoped:表示为组件的每个实例创建一个实例。
    • Unscoped:意味着每次注入()或提供程序调用都会创建一个新实例
    • 注意: Dagger2 仅为@Singleton根组件(及其模块)保留。子组件必须使用自定义范围,但该范围的功能与@Singleton.

现在,回答这个问题:我想说为每个概念上不同的范围创建一个新的命名范围。例如,创建一个@PerActivity@PerFragment@PerView注释,指示组件应在何处实例化,从而指示其生命周期。

注意:这是两个极端之间的折衷。考虑您需要的根组件和n个子组件的情况:

  • 至少2 个注释(@Singleton@SubSingleton),以及
  • 最多 n+1 个注释(@Singleton,@SubSingleton1, ...@SubSingletonN)。

例子:

应用:

/** AppComponent.java **/ 
@Singleton
@Component( modules = AppModule.class )
public interface AppComponent{
    void inject(MainActivity mainActivity);
}

/** AppModule.java **/
@Module
public class AppModule{
    private App app;

    public AppModule(App app){
        this.app = app;
    }

    // For singleton objects, annotate with same scope as component, i.e. @Singleton
    @Provides @Singleton public App provideApp() { return app; }
    @Provides @Singleton public EventBus provideBus() { return EventBus.getDefault(); }
}

分段:

/** Fragment1Component.java **/
@PerFragment
@Component( modules = {Fragment1Module.class}, dependencies = {AppComponent.class} )
public interface Fragment1Component {
    void inject(Fragment1 fragment1);
}

/** Fragment1Module.java **/ 
@Module
public class Fragment1Module {
    // For singleton objects, annotate with same scope as component, i.e. @PerFragment
    @Provides @PerFragment public Fragment1Presenter providePresenter(){
        return new Fragment1Presenter();
    }
}

/** PerFragment.java **/ 
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface PerFragment {}
于 2015-06-22T16:17:15.377 回答
22

你的理解是正确的。命名范围允许您传达意图,但它们都以相同的方式工作。

  • 对于作用域提供者方法,每个 Component 实例将创建 1 个所提供对象的实例。
  • 对于无范围的提供者方法,每个 Component 实例将在需要注入时创建所提供对象的新实例。

Component 实例的生命周期很重要。同一组件的 2 个不同实例将提供不同的对象实例,甚至是作用域实例。

范围名称应指示所提供对象的生命周期(与 Component 实例的生命周期相匹配),因此@PerFragment对我来说更有意义。

快速浏览一下“MVP Presenters...”教程,我并不清楚作者的意图是使用单独的范围。由于这些名称只是一次性的,我不会过多地阅读它。

于 2015-06-22T09:41:53.510 回答