Ogn*_*yan 3 android dependency-injection dagger dagger-2
我有一个图书馆项目/模块,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模块都声明为complete = false和library = true
同时,"主要"文档页面(http://google.github.io/dagger/)指出:
Dagger注释处理器是严格的,如果任何绑定无效或不完整,将导致编译器错误.
后者显然是正确的,因为当试图建立不满意的注入错误时会产生(error: java.lang.String cannot be provided without an @Provides- or @Produces-annotated method).
问题是:是否有可能将这种方法(推迟提供注入)迁移到Dagger 2以及如何?
PS最初我认为这是一个肮脏的解决方法,在库的@Module中提供一些虚拟值,但是又一次 - 你不能在Dagger 2中使用模块覆盖(这是一种WTF(!!!).模块覆盖是最有用的功能我在创建单元测试时).可能我错过了一些非常基本的东西,我希望有人可以指出:-).
Ogn*_*yan 10
事实证明,有专门的构造,但它需要一些时间才能找到它.如果您需要一个具有包含未满足注入的模块的组件 - 请将其设为@Subcomponent.由于文件明确指出:
该关系允许子组件实现在声明时从其父组件继承整个绑定图.因此,在与父组件关联之前,不会评估子组件的完整性
所以在我的情况下,我的图书馆项目需要是一个匕首子组件.当我在我的app项目中使用它时,我的app dagger组件必须包含lib子组件.
在代码中:
库子组件:
@Subcomponent(modules = Mod1.class)
public interface MyLibraryComponent {
void inject(Mod1Interface1 in);
}
Run Code Online (Sandbox Code Playgroud)
应用程序组件:
@Component(modules = Mod2.class)
@Singleton
public interface MyAppComponent {
void inject(MainActivity act);
MyLibraryComponent newMyLibraryComponent();
}
Run Code Online (Sandbox Code Playgroud)
请注意MyLibraryComponent newMyLibraryComponent();- 这就是告诉匕首您的组件包含该子组件的方法.
图形实例化:
MyAppComponent comp = DaggerMyAppComponent.builder().build();
Run Code Online (Sandbox Code Playgroud)
请注意,与dependencies在这种情况下使用具有(@ Component的属性)的组件组合相反,您不必"手动"构造子组件.如果子组件的模块不需要特殊配置(即构造函数参数),组件将"自动"注意这一点.如果某个子组件的模块需要配置,则通过组件实例化执行此操作,如下所示:
MyAppComponent comp = DaggerMyAppComponent.builder().
mod2(new Mod2SpecialConfiguration()).
build();
Run Code Online (Sandbox Code Playgroud)
对于android,如果您的库项目包含活动,则会有一个特殊的变化,因为每个活动都必须"按需"单独注入,这与常规Java应用程序相反,在常规Java应用程序中,您通常在启动时注入整个应用程序一次.
为了举例说明,我们的库项目包含登录活动"ActLogin",我们将其用作多个应用程序的通用.
@Subcomponent(modules = Mod1.class)
public interface MyLibraryComponent {
void injectActLogin(ActLogin act);
void inject(Mod1Interface1 in);
}
Run Code Online (Sandbox Code Playgroud)
问题是在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;
}
}
Run Code Online (Sandbox Code Playgroud)
然后在你的活动中你使用它像这样:
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
((MyApplication) getApplication()).getAppDependencyInjector().inject(this);
// ...
}
Run Code Online (Sandbox Code Playgroud)
但是我们的ActLogin活动是图书馆项目(和匕首组件)的一部分,它不知道将使用什么应用程序,因此我们将如何注入它?
有一个很好的解决方案,但请注意,我不确定它是规范的(即文档中没有提到它,它没有作为"权威"的例子给出(afaik))
首先,您必须在app app组件中扩展library dagger组件:
public interface MyAppComponent extends MyLibraryComponent {
Run Code Online (Sandbox Code Playgroud)
这样您的应用程序组件将包含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();
}
}
Run Code Online (Sandbox Code Playgroud)
那么我们必须MyLibraryComponentProvider在我们Application班上实现:
public class MyApplication extends Application implements
MyLibDependencyInjectionHelper.MyLibraryComponentProvider {
// ...
@Override
public MyLibraryComponent getMyLibraryComponent() {
return (MyLibraryComponent) mAppDependencyInjector;
}
}
Run Code Online (Sandbox Code Playgroud)
在ActLogin我们注入:
public class ActLogin extends Activity {
@Override
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
// ...
MyLibDependencyInjectionHelper.getMyLibraryComponent(getApplication()).
injectActLogin(this);
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
此解决方案存在一个问题:如果您忘记MyLibraryComponentProvider在应用程序中实现,则在编译时不会出现错误,但在启动ActLogin活动时会在运行时出错.幸运的是,通过简单的单元测试可以轻松避免这种情况.