我有一个图书馆项目/模块,Android应用程序和常规Java应用程序都使用它。
在Dagger 1中,该项目/模块具有属性complete = false
。在@Inject字段中,任何类实现或@Provides方法都不满足。我们的想法是强制拥有complete = true
的“顶层”模块提供系统特定的实现
仅为示例:在库项目中,我有ActLogin活动,其中包含字段@Inject @Named("app version") mAppVersion
。登录服务器时使用此字段的值。 ActLogin被几个使用此库的应用程序使用。每个应用的模块都有complete = true
,并通过@Provides @Named("app version") provideAppVersion()
Dagger 2(http://google.github.io/dagger/dagger-1-migration.html)迁移的文档说明:
Dagger 2模块全部声明为完整=假和库=真
同时“主要”文档页面(http://google.github.io/dagger/)声明:
Dagger注释处理器是严格的,如果任何绑定无效或不完整,将导致编译器错误。
后者显然是正确的,因为在尝试使用不满意的注入错误时会产生(error: java.lang.String cannot be provided without an @Provides- or @Produces-annotated method
)。
问题是:是否可以将此方法(推迟提供注入)迁移到Dagger 2以及如何进行?
P.S。最初我认为这是一个肮脏的解决方法,在库的@Module中提供一些虚拟值,但是又一次 - 你不能在Dagger 2中使用模块覆盖(这是一种WTF(!!!)。模块覆盖对我来说是最有用的功能在创建单元测试时)。可能我错过了一些非常基本的东西,我希望有人可以指出: - )。
答案 0 :(得分:10)
事实证明,有专门的构造,但需要一些时间才能找到它。 如果您需要一个具有包含未满足注入的模块的组件 - 请将其设为@Subcomponent。正如文件明确指出:
该关系允许子组件实现在声明时从其父组件继承整个绑定图。出于这个原因,子组件在完成之前不会被评估,直到它与父级相关联
所以在我的情况下,我的图书馆项目需要是一个匕首子组件。当我在我的app项目中使用它时,我的app dagger组件必须包含lib子组件。
在代码中:
库子组件:
@Subcomponent(modules = Mod1.class)
public interface MyLibraryComponent {
void inject(Mod1Interface1 in);
}
应用程序组件:
@Component(modules = Mod2.class)
@Singleton
public interface MyAppComponent {
void inject(MainActivity act);
MyLibraryComponent newMyLibraryComponent();
}
请注意MyLibraryComponent newMyLibraryComponent();
- 这就是告诉匕首您的组件包含该子组件的方法。
图形实例化:
MyAppComponent comp = DaggerMyAppComponent.builder().build();
请注意,与使用dependencies
(@ Component' s属性)的组件构成相反,您不必手动"构建你的子组件。该组件将自动"如果子组件的模块不需要特殊配置(即构造函数参数),请注意这一点。如果某个子组件的模块需要配置,您可以通过组件实例化这样做:
MyAppComponent comp = DaggerMyAppComponent.builder().
mod2(new Mod2SpecialConfiguration()).
build();
对于Android,如果您的图书馆项目包含活动,则会有一个特殊的转折,因为每个活动都必须单独注入"按需提供"与普通的java应用程序相反,你通常在启动时注入整个应用程序。
为了举例,我们说我们的图书馆项目包含登录活动" ActLogin"我们在几个应用程序中使用它们。
@Subcomponent(modules = Mod1.class)
public interface MyLibraryComponent {
void injectActLogin(ActLogin act);
void inject(Mod1Interface1 in);
}
问题是在Android中我们通常在Application对象中创建依赖图,如下所示:
public class MyApplication extends Application {
private MyAppComponent mAppDependencyInjector;
@Override
public void onCreate() {
super.onCreate();
mAppDependencyInjector = DaggerMyAppComponent.builder().build();
}
public MyAppComponent getAppDependencyInjector() {
return mAppDependencyInjector;
}
}
然后在您的活动中,您可以像这样使用它:
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
((MyApplication) getApplication()).getAppDependencyInjector().inject(this);
// ...
}
但是我们的ActLogin
活动是库项目(和dagger组件)的一部分,它不知道它将使用什么应用程序,因此我们将如何注入它?
有一个很好的解决方案,但请注意我不确定它是规范的(即文档中没有提到它,并不是作为一个例子由"权威& #34;(afaik))
Project's source can be found at github
首先,您必须在app app组件中扩展library dagger组件:
public interface MyAppComponent extends MyLibraryComponent {
这样您的应用程序组件将包含子组件中的所有inject
方法,因此您也可以注入它的活动。毕竟,顶级组件实际上是整个对象图(更准确地说是Dagger生成的DaggerMyAppComponent代表整个图形),因此它能够在所有子组件中注入自身+所定义的所有内容。
现在我们必须确保图书馆项目能够访问它。我们创建了一个帮助类:
public class MyLibDependencyInjectionHelper {
public static MyLibraryComponent getMyLibraryComponent(Application app) {
if (app instanceof MyLibraryComponentProvider) {
return ((MyLibraryComponentProvider) app).getMyLibraryComponent();
} else {
throw new IllegalStateException("The Application is not implementing MyLibDependencyInjectionHelper.MyLibraryComponentProvider");
}
}
public interface MyLibraryComponentProvider {
MyLibraryComponent getMyLibraryComponent();
}
}
然后我们必须在MyLibraryComponentProvider
课程中实施Application
:
public class MyApplication extends Application implements
MyLibDependencyInjectionHelper.MyLibraryComponentProvider {
// ...
@Override
public MyLibraryComponent getMyLibraryComponent() {
return (MyLibraryComponent) mAppDependencyInjector;
}
}
在ActLogin我们注入:
public class ActLogin extends Activity {
@Override
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
// ...
MyLibDependencyInjectionHelper.getMyLibraryComponent(getApplication()).
injectActLogin(this);
// ...
}
}
此解决方案存在问题:如果您忘记在应用程序中实现MyLibraryComponentProvider
,则在编译时不会出现错误,但在启动ActLogin活动时会在运行时出错。幸运的是,通过简单的单元测试可以轻松避免这种情况。