我使用 dagger2 已经有一段时间了。我对为每个 Activity/fragment 创建自己的组件/模块感到困惑。请帮我澄清一下:
例如,我们有一个应用程序,该应用程序大约有 50 个屏幕。
我们将按照 MVP 模式和 Dagger2 为 DI 实现代码。假设我们有 50 个 Activity 和 50 个演示者。
在我看来,通常我们应该这样组织代码:
@Module
public class AppModule {
private final MyApplicationClass application;
public AppModule(MyApplicationClass application) {
this.application = application;
}
@Provides
@Singleton
Context provideApplicationContext() {
return this.application;
}
//... and many other providers
}
@Singleton
@Component( modules = { AppModule.class } )
public interface AppComponent {
Context getAppContext();
Activity1Component plus(Activity1Module module);
Activity2Component plus(Activity2Module module);
//... plus 48 methods for 48 other activities. Suppose that we don't have any other Scope (like UserScope after user login, ....)
}
@Scope
@Documented
@Retention(value=RUNTIME)
public @interface ActivityScope {
}
@Module
public class Activity1Module {
public LoginModule() {
}
@Provides
@ActivityScope
Activity1Presenter provideActivity1Presenter(Context context, /*...some other params*/){
return new Activity1PresenterImpl(context, /*...some other params*/);
}
}
@ActivityScope
@Subcomponent( modules = { Activity1Module.class } )
public interface Activity1Component {
void inject(Activity1 activity); // inject Presenter to the Activity
}
// .... Same with 49 remaining modules and components.
这些只是非常简单的例子来展示我将如何实现这一点。
但是我的一个 friend 刚刚给了我另一个实现:
@Module
public class AppPresenterModule {
@Provides
Activity1Presenter provideActivity1Presentor(Context context, /*...some other params*/){
return new Activity1PresenterImpl(context, /*...some other params*/);
}
@Provides
Activity2Presenter provideActivity2Presentor(Context context, /*...some other params*/){
return new Activity2PresenterImpl(context, /*...some other params*/);
}
//... same with 48 other presenters.
}
@Module
public class AppModule {
private final MyApplicationClass application;
public AppModule(MyApplicationClass application) {
this.application = application;
}
@Provides
@Singleton
Context provideApplicationContext() {
return this.application;
}
//... and many other provides
}
@Singleton
@Component(
modules = { AppModule.class, AppPresenterModule.class }
)
public interface AppComponent {
Context getAppContext();
public void inject(Activity1 activity);
public void inject(Activity2 activity);
//... and 48 other methods for 48 other activities. Suppose that we don't have any other Scope (like UserScope after user login, ....)
}
他的解释是:他不必为每个 Activity 创建组件和模块。
我觉得我 friend 的想法绝对不好,但如果我错了,请纠正我。原因如下:
很抱歉发表了很长的帖子,但请帮我为我和我的 friend 澄清这一点,我无法说服他。
您的意见将不胜感激。
/------------------------------------------------- ---------------/
做一个演示后编辑。
首先,感谢@pandawarrior 的回答。
在问这个问题之前,我应该创建一个演示。我希望我在这里的结论可以帮助别人。
所以,我上面说的所有理由大多是错误的。但这并不意味着我们应该遵循我 friend 的想法,原因有二:
在我看来,用一个小应用程序(只有几个屏幕,没有很多依赖或类似的依赖),我们可以应用我 friend 的想法,但当然不推荐。
更喜欢阅读以下内容:
What determines the lifecycle of a component (object graph) in Dagger 2?
Dagger2 activity scope, how many modules/components do i need?
还有一点要注意:如果你想看看对象什么时候被销毁,你可以一起调用方法的那些,GC会立即运行:
System.runFinalization();
System.gc();
如果你只使用其中一种方法,GC 会运行得更晚,你可能会得到错误的结果。
最佳答案
为每个 Activity
声明一个单独的模块根本不是一个好主意。为每个 Activity
声明单独的组件更糟。这背后的原因很简单——您并不真正需要所有这些模块/组件(正如您自己已经看到的那样)。
但是,只有一个与 Application
相关联的组件的生命周期并将其用于注入(inject)所有 Activities
也不是最佳解决方案(这是您 friend 的方法)。它不是最佳的,因为:
@Singleton
或自定义范围) Services
也是,但是 Services
可以需要与 Activities
不同的对象(例如 Services
不需要演示者,不需要 FragmentManager
等)。通过使用单个组件,您失去了为不同组件定义不同对象图的灵活性。 因此,每个
Activity
的一个组件是一种矫枉过正,但整个应用程序的单个组件不够灵活。最佳解决方案介于这些极端之间(通常如此)。我使用以下方法:
Application
. Activities
和 Fragments
)。在每个 Activity
中实例化和 Fragment
. Services
所需的对象.在每个 Service
中实例化. 以下是如何实现相同方法的示例。
2017 年 7 月编辑
我发布了一个视频教程,展示了如何在 Android 应用程序中构建 Dagger 依赖注入(inject)代码:Android Dagger for Professionals Tutorial .
2018 年 2 月编辑
我发表了一篇 complete course about dependency injection in Android .
在本类(class)中,我解释了依赖注入(inject)的理论,并展示了它是如何在 Android 应用程序中自然出现的。然后我演示了 Dagger 构造如何适应一般的依赖注入(inject)方案。
如果您参加本类(class),您将理解为什么为每个 Activity/fragment 单独定义模块/组件的想法在最基本的方面基本上是有缺陷的。
这种方法使表示层的结构从“功能”类集合镜像到“构造”类集合结构,从而将它们耦合在一起。这违背了依赖注入(inject)的主要目标,即保持类的“构造”和“功能”集不相交。
适用范围:
@ApplicationScope
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
// Each subcomponent can depend on more than one module
ControllerComponent newControllerComponent(ControllerModule module);
ServiceComponent newServiceComponent(ServiceModule module);
}
@Module
public class ApplicationModule {
private final Application mApplication;
public ApplicationModule(Application application) {
mApplication = application;
}
@Provides
@ApplicationScope
Application applicationContext() {
return mApplication;
}
@Provides
@ApplicationScope
SharedPreferences sharedPreferences() {
return mApplication.getSharedPreferences(Constants.PREFERENCES_FILE, Context.MODE_PRIVATE);
}
@Provides
@ApplicationScope
SettingsManager settingsManager(SharedPreferences sharedPreferences) {
return new SettingsManager(sharedPreferences);
}
}
Controller 范围:
@ControllerScope
@Subcomponent(modules = {ControllerModule.class})
public interface ControllerComponent {
void inject(CustomActivity customActivity); // add more activities if needed
void inject(CustomFragment customFragment); // add more fragments if needed
void inject(CustomDialogFragment customDialogFragment); // add more dialogs if needed
}
@Module
public class ControllerModule {
private Activity mActivity;
private FragmentManager mFragmentManager;
public ControllerModule(Activity activity, FragmentManager fragmentManager) {
mActivity = activity;
mFragmentManager = fragmentManager;
}
@Provides
@ControllerScope
Context context() {
return mActivity;
}
@Provides
@ControllerScope
Activity activity() {
return mActivity;
}
@Provides
@ControllerScope
DialogsManager dialogsManager(FragmentManager fragmentManager) {
return new DialogsManager(fragmentManager);
}
// @Provides for presenters can be declared here, or in a standalone PresentersModule (which is better)
}
然后在
Activity
:public class CustomActivity extends AppCompatActivity {
@Inject DialogsManager mDialogsManager;
private ControllerComponent mControllerComponent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getControllerComponent().inject(this);
}
private ControllerComponent getControllerComponent() {
if (mControllerComponent == null) {
mControllerComponent = ((MyApplication)getApplication()).getApplicationComponent()
.newControllerComponent(new ControllerModule(this, getSupportFragmentManager()));
}
return mControllerComponent;
}
}
关于依赖注入(inject)的附加信息:
Dagger 2 Scopes Demystified
Dependency Injection in Android
关于android - Dagger- 我们应该为每个 Activity/fragment 创建每个组件和模块吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36206989/