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

Enr*_*ico 126 java lifecycle dagger-2

我试图围绕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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

编辑

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

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

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

我的理解

匕首1.x

依赖性是否是@Singleton.根图和子图中的依赖性同样如此,导致依赖关系绑定到哪个图形的模糊性(参见In Dagger是缓存的子图中的单例,或者当新的活动子图时它们总是被重新创建)是构造?)

匕首2.0

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

// 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");
    }
}
Run Code Online (Sandbox Code Playgroud)
// Our custom scope
@Scope public @interface PerActivity {}
Run Code Online (Sandbox Code Playgroud)
// 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");
    }
}
Run Code Online (Sandbox Code Playgroud)
// 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;
    }

}
Run Code Online (Sandbox Code Playgroud)

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

综上所述

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

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

$ 64k问题*

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

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

Epi*_*rce 66

至于你的问题

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

简短的回答是你确定它.您的组件可以被赋予范围,例如

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

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {
}
Run Code Online (Sandbox Code Playgroud)

这些对你有用两件事:

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

.

@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();
    }
}
Run Code Online (Sandbox Code Playgroud)
  • 允许对范围内的依赖项进行子范围设定,从而允许您创建"子范围"组件,该组件使用"superscoped"组件中提供的实例.

这可以通过@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));
Run Code Online (Sandbox Code Playgroud)

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

@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();
Run Code Online (Sandbox Code Playgroud)

重要的事情要知道:

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

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