我们使用了RoboGuice,但它已被弃用我开始用Dagger2替换它。
// https://github.com/google/dagger
compile('com.google.dagger:dagger:2.7')
annotationProcessor 'com.google.dagger:dagger-compiler:2.7'
provided 'org.glassfish:javax.annotation:10.0-b28'
@Module
public class ApplicationModule {
Application mApp;
public ApplicationModule(@NonNull Application app) {
Preconditions.checkNotNull(app);
mApp = app;
}
@Provides
@Singleton
public SharedPreferences providesSharedPrefs() {
return PreferenceManager.getDefaultSharedPreferences(mApp);
}
@Provides
@Singleton
public DateHelper providesDateHelper() {
return new DateHelper(mApp);
}
@Provides
@Singleton
public PersistentConfig providesPersistentConfig() {
return new PersistentConfig(mApp);
}
@Provides
@Singleton
public OttoBus providesOttoBus() {
return new OttoBus();
}
}
public class Application extends MultiDexApplication {
private ApplicationComponent mApplicationComponent;
@Override
public void onCreate() {
super.onCreate();
mApplicationComponent = DaggerApplicationComponent.builder()
.applicationModule(new ApplicationModule(this))
.build();
mApplicationComponent.inject(this);
}
public static Application getApp(@NonNull Context context) {
return (Application) context.getApplicationContext();
}
public static ApplicationComponent getApplicationComponent(@NonNull Context context) {
return getApp(context).getApplicationComponent();
}
}
在我想要注入ApplicationComponent
的任何地方之后例如MainActivity
public class MainActivity extends AppCompatActivity {
@Inject
PersistentConfig mPersistentConfig;
@Inject
OttoBus mOttoBus;
@Override
public void onCreate(Bundle savedInstanceState) {
Helper.manageRotation(this);
super.onCreate(null);
setContentView(R.layout.main_layout);
Application.getApplicationComponent(this).inject(this);
}
}
Application.getApplicationComponent(context).inject(this);
第一个问题:我真的很担心interface ApplicationComponent
必须提供所有活动/片段/服务(等),我想使用注入。但我不能使用像Activity / Fragment
这样的通用对象。或者我真的不在乎现实,也不明白Dagger2是如何运作的?
因为这对于拥有大约50多项活动和大量片段/服务的项目来说真的很疯狂......
@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void inject(@NonNull Application app);
void inject(@NonNull MainActivity object);
void inject(@NonNull DispatcherActivity object);
void inject(@NonNull DateTimeHelper object);
void inject(@NonNull DatabaseHelper object);
void inject(@NonNull LandingPageActivityFragment object);
void inject(@NonNull RedirectActivity object);
void inject(@NonNull CategoryFragment object);
void inject(@NonNull BaseModuleFragment object);
void inject(@NonNull NotificationHelper object);
void inject(@NonNull RecordAdapter object);
void inject(@NonNull PagingProvider object);
void inject(@NonNull FilterDialog object);
... next 100+ injections?
}
我说,这不可能是真的...
第二个问题:当我不能像void inject(@NonNull NotificationHelper<? extends GenericObject> object);
那样使用它时,如何提供注入泛型类,因为它需要特定的对象。所以我必须在ApplicationComponent
内写下所有这些对象,而不是使用?
表示法?
这不仅仅是疯狂:(。也许更好的留在RoboGuice,这是更开发人员友好,不需要这个开销和手动检查每个注入的对象?当我忘了添加到这个列表,我会在运行时获取NPE
(当我不会对它进行大量测试时,它会使客户崩溃)。
手动编写它比在不可能使用Activity / Fragment / Service
这样的通用对象时创建所有对象的列表要快得多。
是否有更好的解决方案,当我不想使用相同的通用BaseActivity
时会注入ApplicationModule
的每个部分,并且每个活动都会被这个巨大的BaseActivity
扩展?< / p>
答案 0 :(得分:2)
此问题涉及投诉方面,但尝试回答:
我真的很困惑接口ApplicationComponent,它必须提供我想要使用注入的所有活动/片段/服务(等)。但我不能使用像Activity / Fragment这样的通用对象。或者我真的不在乎现实,也不明白Dagger2是如何运作的?
这确实是Dagger 2的工作原理;它必须静态地提供进样器(组件)内注射目标的类型,并且不能使用'通用'(协变)类型。 Dagger 2这样做是为了维持100%静态的DI框架。
请注意,您将RecordAdapter
和DatabaseHelper
指定为注射网站。您可能不需要这样做,您应该尝试仅指定构造函数不可见的顶级对象(Activity
,Fragment
和Service
)作为注入站点。其余的对象应该能够通过用@Inject
注释它们的依赖关系并在Module
中指定它们的依赖关系(如果有的话)来构建。
也许最好留在RoboGuice,这对开发人员更友好,不需要花费这个开销并手动检查每个注入的对象
是的,Roboguice更友好,因为您不必担心指定注射目标。但是,请考虑以下Roboguice中的内容:1。错误地设置对象图时得到的“死亡的红色堆栈跟踪” 2.您无法通过Find Usages查看哪些接口实现正在您的项目中使用,这也可能是“开发人员不友好”
是否有更好的解决方案,当我不想使用相同的通用BaseActivity时,它会注入ApplicationModule的每个部分,并且每个活动都会被这个巨大的BaseActivity扩展?
嗯,这将取决于您使用的依赖项和位置。如果你有一个小的依赖关系列表,你想要到处,那么这可能是最好的解决方案,即制作一个BaseActivity
来接收这些依赖关系并使其可用于你的所有子类。或者,您可以使用子组件和模块来划分对象图,以便您可以将使用者/注入目标与正确的模块组合在一起。然后你不需要有一个列出所有注射部位的“神”组件。
第二个问题:当我无法像void注入那样使用它时,如何提供注入泛型类(@NonNull NotificationHelper对象);因为它需要特定的对象。所以我必须在ApplicationComponent中编写所有这些对象而不使用?符号
是的,您必须提供注射目标的不变类型。我不确定您的NotificationHelper<String>
是否是顶级类型。当您注入Fragment
,Activity
或Service
时,为什么不通过对象图注入它?
如果绝对必须是注射目标,则需要子类:NotificationHelper<String>
和Notification<Integer>
成为StringNotificationHelper extends NotificationHelper<String>
,IntegerNotficationHelper extends NotificationHelper<Integer>
。这是“清洁代码”一书中推荐的做法。
您不需要在ApplicationComponent中写入所有注入站点,您可以创建与项目中依赖项的使用模式相对应的子组件。
(披露:作为正在尝试将项目从Roboguice迁移到Dagger 2的人,我对您的投诉表示同情)
答案 1 :(得分:1)
谢谢,我们就像你一周前描述的那样解决了它。使用每个对象注入。
更好的解决方案是不要只使用inject
但复杂的名称。为什么?因为它有助于解决为什么没有注入某些对象(你知道,基类等)。
@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {
void injectApplication(@NonNull Application app);
void injectMainActivity(@NonNull MainActivity object);
void injectDispatcherActivity(@NonNull DispatcherActivity object);
...
}
我们最终使用的是通用性UtilityWrapper
,如下所述:https://medium.com/@patrykpoborca/dagger-2-and-base-classes-generics-and-presenter-injection-7d82053080c#.b58ykd4cm