首页 文章

什么决定了Dagger 2中组件(对象图)的生命周期?

提问于
浏览
119

我试图围绕Dagger 2中的范围,特别是范围图的生命周期 . 如何创建一个在离开示波器时将被清理的组件 .

对于Android应用程序,使用Dagger 1.x通常在应用程序级别具有根范围,您可以扩展该范围以在活动级别创建子范围 .

public class MyActivity {

    private ObjectGraph mGraph;

    public void onCreate() {
        mGraph = ((MyApp) getApplicationContext())
            .getObjectGraph()
            .plus(new ActivityModule())
            .inject(this);
    }

    public void onDestroy() {
        mGraph = null;
    }
}

只要您保留对它的引用,子范围就存在,在这种情况下,它是您的Activity的生命周期 . 删除onDestroy中的引用可确保范围图可以自由地进行垃圾回收 .

EDIT

杰西威尔逊最近发布了mea culpa

Dagger 1.0严重搞砸了它的范围名称...... @Singleton注释用于根图和自定义图形,因此弄清楚事物的实际范围是很棘手的 .

我读过/听过的所有其他内容都指向Dagger 2改进了范围的工作方式,但我很难理解其中的差异 . 根据@Kirill Boyarshinov在下面的评论,组件或依赖关系的生命周期仍然像往常一样通过具体的引用来确定 . 那么Dagger 1.x和2.0范围之间的差异纯粹是语义清晰度的问题吗?

我的理解

Dagger 1.x

依赖性是 @Singleton 或不是 . 对于根图和子图中的依赖关系同样如此,导致依赖关系绑定到哪个图表的模糊性(参见In Dagger are Singletons within the sub-graph cached or will they always be recreated when a new activity sub-graph is constructed?

Dagger 2.0

自定义作用域允许您创建语义清晰的作用域,但在功能上等同于在Dagger 1.x中应用 @Singleton .

// Application level
@Singleton
@Component( modules = MyAppModule.class )
public interface MyAppComponent {
    void inject(Application app);
}

@Module
public class MyAppModule {

    @Singleton @Named("SingletonScope") @Provides
    StringBuilder provideStringBuilderSingletonScope() {
        return new StringBuilder("App");
    }
}

// Our custom scope
@Scope public @interface PerActivity {}

// Activity level
@PerActivty
@Component(
    dependencies = MyAppComponent.class,
    modules = MyActivityModule.class
)
public interface MyActivityComponent {
    void inject(Activity activity);
}

@Module
public class MyActivityModule {

    @PerActivity @Named("ActivityScope") @Provides
    StringBuilder provideStringBuilderActivityScope() {
        return new StringBuilder("Activity");
    }

    @Name("Unscoped") @Provides
    StringBuilder provideStringBuilderUnscoped() {
        return new StringBuilder("Unscoped");
    }
}

// Finally, a sample Activity which gets injected
public class MyActivity {

    private MyActivityComponent component;

    @Inject @Named("AppScope")
    StringBuilder appScope

    @Inject @Named("ActivityScope")
    StringBuilder activityScope1

    @Inject @Named("ActivityScope")
    StringBuilder activityScope2

    @Inject @Named("Unscoped")
    StringBuilder unscoped1

    @Inject @Named("Unscoped")
    StringBuilder unscoped2

    public void onCreate() {
        component = Dagger_MyActivityComponent.builder()
            .myApplicationComponent(App.getComponent())
            .build()
            .inject(this);

        appScope.append(" > Activity")
        appScope.build() // output matches "App (> Activity)+" 

        activityScope1.append("123")
        activityScope1.build() // output: "Activity123"

        activityScope2.append("456")
        activityScope1.build() // output: "Activity123456"

        unscoped1.append("123")
        unscoped1.build() // output: "Unscoped123"

        unscoped2.append("456")
        unscoped2.build() // output: "Unscoped456"

    }

    public void onDestroy() {
        component = null;
    }

}

需要注意的是,使用 @PerActivity 会传达您对该组件生命周期的意图,但最终您可以随时随地使用该组件 . Dagger唯一的承诺是,对于给定的组件,范围注释方法将返回单个实例 . 我还假设Dagger 2在组件上使用范围注释来验证模块只提供在同一范围或非范围内的依赖关系 .

摘要

依赖关系仍然是单例或非单例,但 @Singleton 现在用于应用程序级单例实例,自定义范围是用较短生命周期注释单例依赖关系的首选方法 .

开发人员负责通过删除不再需要的引用来管理组件/依赖项的生命周期,并负责确保组件仅在其预期范围内创建一次,但自定义范围注释使得更容易识别该范围 .

$ 64k问题*

我对Dagger 2范围和生命周期的理解是否正确?

*实际上不是64,000美元的问题 .

1 回答

  • 61

    至于你的问题

    什么决定了Dagger 2中组件(对象图)的生命周期?

    简短的回答是 you determine it . 您的组件可以被赋予范围,例如

    @Scope
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ApplicationScope {
    }
    
    @Scope
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ActivityScope {
    }
    

    这些对你有用两件事:

    • 范围验证:组件只能包含未组装的提供程序,或与组件具有相同范围的范围提供程序 .

    .

    @Component(modules={ApplicationModule.class})
    @ApplicationScope
    public interface ApplicationComponent {
        Something something();
        AnotherThing anotherThing();
    
        void inject(Whatever whatever);
    }
    
    @Module
    public class ApplicationModule {
        @ApplicationScope //application-scoped provider, only one can exist per component
        @Provides
        public Something something() {
             return new Something();
        }
    
        @Provides //unscoped, each INJECT call creates a new instance
        public AnotherThing anotherThing() {
            return new AnotherThing();
        }
    }
    
    • 允许对作用域依赖项进行子作用域,从而允许您创建使用"superscoped"组件中提供的实例的"subscoped"组件 .

    这可以使用 @Subcomponent 注释或组件依赖性来完成 . 我个人更喜欢依赖 .

    @Component(modules={ApplicationModule.class})
    @ApplicationScope
    public interface ApplicationComponent {
        Something something();
        AnotherThing anotherThing();
    
        void inject(Whatever whatever);
    
        ActivityComponent newActivityComponent(ActivityModule activityModule); //subcomponent factory method
    }
    
    @Subcomponent(modules={ActivityModule.class})
    @ActivityScope
    public interface ActivityComponent {
        ThirdThingy thirdThingy();
    
        void inject(SomeActivity someActivity);
    }
    
    @Module
    public class ActivityModule {
        private Activity activity;
    
        public ActivityModule(Activity activity) {
            this.activity = activity;
        }
    
        //...
    }
    
    ApplicationComponent applicationComponent = DaggerApplicationComponent.create();
    ActivityComponent activityComponent = applicationComponent.newActivityComponent(new ActivityModule(SomeActivity.this));
    

    或者你可以像这样使用组件依赖

    @Component(modules={ApplicationModule.class})
    @ApplicationScope
    public class ApplicationComponent {
        Something something(); 
        AnotherThing anotherThing();
    
        void inject(Whatever whatever);
    }
    
    @Component(dependencies={ApplicationComponent.class}, modules={ActivityModule.class})
    @ActivityScope
    public interface ActivityComponent extends ApplicationComponent {
        ThirdThingy thirdThingy();
    
        void inject(SomeActivity someActivity);
    }
    
    @Module
    public class ActivityModule {
        private Activity activity;
    
        public ActivityModule(Activity activity) {
            this.activity = activity;
        }
    
        //...
    }
    
    ApplicationComponent applicationComponent = DaggerApplicationComponent.create();
    ActivityComponent activityComponent = DaggerActivityComponent.builder().activityModule(new ActivityModule(SomeActivity.this)).build();
    

    重要的事情要知道:

    • 作用域提供程序为该给定作用域 for each component 创建一个实例 . 意味着组件跟踪其自己的实例,但其他组件没有共享范围池或某些魔术 . 要在给定范围内拥有一个实例,您需要一个组件实例 . 这就是您必须提供 ApplicationComponent 来访问其自己的作用域依赖项的原因 .

    • 组件只能包含一个范围组件 . 不允许多个范围的组件依赖项 .

相关问题