Dagger2 向组件添加范围标记的目的是什么?
Dagger2 what is the purpose of adding a scope tag to components?
我创建了一个组件,它仅在 activity 的生命周期内有效。我没有使用任何范围注释,只是组件生命周期的快速示例如下所示:
public class MainActivity extends AppCompatActivity {
private final String TAG = getClass().getSimpleName();
@Inject
AlmondButter someAlmondButter;
@Inject
CashewSandwich sandwich;
SandwichComponent sandwichComponent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*create thte dependent butter for the sandwich here*/
ButterComponent butterComponent=DaggerButterComponent.builder().
butterModule(new ButterModule()).build();
/*create a scope sandwichcomponent here */
sandwichComponent=DaggerSandwichComponent.builder().sandwichModule(new SandwichModule()).
butterComponent(butterComponent)
.build();
//finally we have a sandwichComponent, lets inject our dependencies
sandwichComponent.inject(this);
Log.v(TAG,sandwich.toString());
Log.v(TAG,someAlmondButter.toString());
}
@Override
protected void onDestroy() {
super.onDestroy();
//not necessary but it clearly shows the scope being tied to lifecycle of activity
sandwichComponent=null;
}
}
none 我的组件在注释范围内并且工作正常。所以我很困惑为什么有些人建议创建范围标签,目的是什么?我将在下面向您展示我的组件以供参考:
@Component(dependencies = ButterComponent.class, modules = SandwichModule.class)
public interface SandwichComponent {
CashewSandwich ProvideCashewSandwitch();
void inject (MainActivity mainactivity);
}
和下一个组件:
@Component(modules={ButterModule.class})
public interface ButterComponent {
//these are for our whatever class depends on butter
AlmondButter ProvideAlmondButter();
CashewButter ProvideCashewButter();
}
更新:对于需要帮助理解这些概念的任何人,我创建了一个博客 HERE.
范围管理同一类型的多个请求中的实例创建。想象一下,如果你有这个:
@Inject
AlmondButter someAlmondButter;
@Inject
AlmondButter otherAlmondButter;
这将创建两个单独的 AlmondButter
实例。一个微不足道的案例,但希望它能说明每次您请求依赖项时都会创建一个新依赖项的要点。
想象一下,现在您有两个不同的 类,每个都有一个字段 @Inject AlmondButter sharedAlmondButter
。如果您希望它们具有完全相同的实例,范围将为您处理。
同样,对于任何依赖项,您都可以注入 Provider<T>
,即 @Inject Provider<AlmondButter> almondButterProvider
。这可以让您调用 almondButterProvider.get()
来检索新实例。如果您随后希望 .get()
返回的所有值都是同一个实例,范围将完成相同的事情。
通过在组件上使用作用域和在模块提供者方法上使用作用域,您可以要求 Dagger2 为您创建 scoped providers
。
为了在您的模块的提供者方法中获得范围内的提供者,您还必须将范围放在组件上。
您只能在给定组件上指定一个作用域,并且在一个作用域组件中,您只能在其提供者方法上具有该作用域的模块,或者提供者方法也可以是非作用域的。
Unscoped 提供程序在每次注入调用时都会为您提供一个新实例。
作用域提供程序为每个对该特定组件实例的注入调用存储一个实例。
@Component(modules={HelloModule.class})
@Singleton
public interface HelloComponent {
Hello hello();
World world();
void inject(MainActivity mainActivity);
}
@Module
public class HelloModule {
@Provides
public Hello hello() { return new Hello(); } //new instance each call to inject
@Provides
@Singleton
public World world() { return new World(); } //one instance per component
}
同样值得注意的是,如果你子作用于另一个组件来继承它的依赖(使用子组件或组件依赖),你只能依赖另一个作用域的组件。把它想象成 "multiple inheritance" 在 Java 中是不允许的,你也不能依赖多个范围的组件并继承它们的依赖关系,只有一个。
通常你有一个单例作用域,并且你根据应用程序中模块的顶级分离对你的组件进行子作用域。
@Component(modules={ApplicationModule.class})
@Singleton
public interface ApplicationComponent {
Something something();
}
@Component(dependencies={ApplicationComponent.class}, modules={MainActivityModule.class})
@ActivityScope
//this is a subscoped component that inherits from ApplicationComponent
public interface MainActivityComponent extends ApplicationComponent {
OtherThing otherThing();
void inject(MainActivity mainActivity);
}
根据 Martin Fowler 的说法,the right way to slice your application into pieces on the top-level is by features, such as GalleryComponent
, SettingsComponent
, etc. and not by layers (data, domain, presentation).
我创建了一个组件,它仅在 activity 的生命周期内有效。我没有使用任何范围注释,只是组件生命周期的快速示例如下所示:
public class MainActivity extends AppCompatActivity {
private final String TAG = getClass().getSimpleName();
@Inject
AlmondButter someAlmondButter;
@Inject
CashewSandwich sandwich;
SandwichComponent sandwichComponent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*create thte dependent butter for the sandwich here*/
ButterComponent butterComponent=DaggerButterComponent.builder().
butterModule(new ButterModule()).build();
/*create a scope sandwichcomponent here */
sandwichComponent=DaggerSandwichComponent.builder().sandwichModule(new SandwichModule()).
butterComponent(butterComponent)
.build();
//finally we have a sandwichComponent, lets inject our dependencies
sandwichComponent.inject(this);
Log.v(TAG,sandwich.toString());
Log.v(TAG,someAlmondButter.toString());
}
@Override
protected void onDestroy() {
super.onDestroy();
//not necessary but it clearly shows the scope being tied to lifecycle of activity
sandwichComponent=null;
}
}
none 我的组件在注释范围内并且工作正常。所以我很困惑为什么有些人建议创建范围标签,目的是什么?我将在下面向您展示我的组件以供参考:
@Component(dependencies = ButterComponent.class, modules = SandwichModule.class)
public interface SandwichComponent {
CashewSandwich ProvideCashewSandwitch();
void inject (MainActivity mainactivity);
}
和下一个组件:
@Component(modules={ButterModule.class})
public interface ButterComponent {
//these are for our whatever class depends on butter
AlmondButter ProvideAlmondButter();
CashewButter ProvideCashewButter();
}
更新:对于需要帮助理解这些概念的任何人,我创建了一个博客 HERE.
范围管理同一类型的多个请求中的实例创建。想象一下,如果你有这个:
@Inject
AlmondButter someAlmondButter;
@Inject
AlmondButter otherAlmondButter;
这将创建两个单独的 AlmondButter
实例。一个微不足道的案例,但希望它能说明每次您请求依赖项时都会创建一个新依赖项的要点。
想象一下,现在您有两个不同的 类,每个都有一个字段 @Inject AlmondButter sharedAlmondButter
。如果您希望它们具有完全相同的实例,范围将为您处理。
同样,对于任何依赖项,您都可以注入 Provider<T>
,即 @Inject Provider<AlmondButter> almondButterProvider
。这可以让您调用 almondButterProvider.get()
来检索新实例。如果您随后希望 .get()
返回的所有值都是同一个实例,范围将完成相同的事情。
通过在组件上使用作用域和在模块提供者方法上使用作用域,您可以要求 Dagger2 为您创建 scoped providers
。
为了在您的模块的提供者方法中获得范围内的提供者,您还必须将范围放在组件上。
您只能在给定组件上指定一个作用域,并且在一个作用域组件中,您只能在其提供者方法上具有该作用域的模块,或者提供者方法也可以是非作用域的。
Unscoped 提供程序在每次注入调用时都会为您提供一个新实例。 作用域提供程序为每个对该特定组件实例的注入调用存储一个实例。
@Component(modules={HelloModule.class})
@Singleton
public interface HelloComponent {
Hello hello();
World world();
void inject(MainActivity mainActivity);
}
@Module
public class HelloModule {
@Provides
public Hello hello() { return new Hello(); } //new instance each call to inject
@Provides
@Singleton
public World world() { return new World(); } //one instance per component
}
同样值得注意的是,如果你子作用于另一个组件来继承它的依赖(使用子组件或组件依赖),你只能依赖另一个作用域的组件。把它想象成 "multiple inheritance" 在 Java 中是不允许的,你也不能依赖多个范围的组件并继承它们的依赖关系,只有一个。
通常你有一个单例作用域,并且你根据应用程序中模块的顶级分离对你的组件进行子作用域。
@Component(modules={ApplicationModule.class})
@Singleton
public interface ApplicationComponent {
Something something();
}
@Component(dependencies={ApplicationComponent.class}, modules={MainActivityModule.class})
@ActivityScope
//this is a subscoped component that inherits from ApplicationComponent
public interface MainActivityComponent extends ApplicationComponent {
OtherThing otherThing();
void inject(MainActivity mainActivity);
}
根据 Martin Fowler 的说法,the right way to slice your application into pieces on the top-level is by features, such as GalleryComponent
, SettingsComponent
, etc. and not by layers (data, domain, presentation).