我有一个库项目/模块,Android应用程序和普通java应用程序都使用它。在Dagger 1中,此项目/模块具有属性complete=false
。其中有一个@Inject字段,任何类实现或@Provides方法都不能满足该字段。其想法是强制具有complete=true
的“顶部”模块提供特定于系统的实现
举个例子:在library项目中,我有一个ActLogin活动,它有字段@Inject@Named(“app version”)mAppVersion
。此字段的值在登录到服务器时使用。ActLogin由使用此库的多个应用程序使用。每个应用程序的模块都具有complete=true
,并使用@provides@Named(“应用程序版本”)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不能在没有@Provides-或@products注释方法的情况下提供
)。
问题是:是否有可能将这种方法(推迟提供注入)迁移到Dagger2,以及如何迁移?
另外,最初我认为在库的@Module中提供一些虚拟值是一个肮脏的解决办法,但再次强调,Dagger 2中不能有模块重写(这是一种WTF(!!!)。模块重写是我创建单元测试时最有用的功能)。可能我遗漏了一些非常基本的东西,我希望有人能指出:-)。
事实证明,有专门的构造,但需要一些时间来找到它。如果您需要有一个组件,该组件有一个包含未满足注入的模块——让它成为@子组件。正如留档明确指出:
该关系允许子组件实现在声明时从其父级继承整个绑定图。因此,在子组件与父组件关联之前,不会评估其完整性
所以在我的例子中,我的库项目需要是一个匕首子组件。当我在我的应用程序项目中使用它时,我的应用程序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();
-这就是你告诉dagger你的组件包含那个子组件的方式。
图形实例化:
MyAppComponent comp = DaggerMyAppComponent.builder().build();
请注意,在这种情况下,与使用具有依赖项的组件组合相反(@component's property),您不必“手动”构造子组件。如果子组件的模块不需要特殊配置(即构造函数参数),组件将“自动”处理该问题。如果某个子组件的模块需要配置,您可以通过如下组件实例化进行配置:
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中,我们通常在应用程序对象中创建依赖关系图,如下所示:
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活动是库项目(和匕首组件)的一部分,它不知道它将在什么应用程序中使用,所以我们如何注入它?
有一个很好的解决方案,但请注意,我不确定它是否规范(即,文档中没有提到,它不是“权威机构”(afaik)给出的示例)
项目的源代码可以在github上找到。
首先,您必须扩展应用程序组件中的库匕首组件:
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
:
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活动时出现错误。幸运的是,这可以通过简单的单元测试轻松避免。
我正在使用Dagger 2,在为我的类实现测试时,模块中的generate singleton providers存在一些问题。 所以我有两个问题。 > 我不能使用构造函数注入,因为有一个默认的构造函数。如何从测试模块中获取Foo? 在和中,如何确保在运行每个测试时创建的新实例? 谢谢
我想在单元测试模块中使用我的领域管理器。我做的 然后我想实现 但是realmManager为空。如何使用匕首2编写简单的模块测试?我用了匕首模拟,但没有用。我的模块包含 我尝试了谷歌的一切,但我不知道如何从图形中注入对象。
这很好,但是如果我使用全局组件甚至子组件中的一个模块,那么应该传入上下文。因此,这意味着如果我用匕首注入演示器,它将被绑定到ApplicationContext。这使得作为JUnit进行测试变得困难。Android代码不应该在演示器中。 所以我想问的是,最好的做法是只在活动、片段、广播接收器和服务中使用匕首吗?就mvp架构而言,这就是。另一个解决方案是设计另一个dagger组件,但不是与appco
我找到了静态编程语言Lazy对象的答案,在这里使用:静态编程语言:检查Lazy val是否已初始化 但看起来像匕首。Lazy没有相同的公共方法。 这就是我如何懒洋洋地使用Dagger注射: 如何在不调用someService的情况下检查someService是否已初始化。get()哪个将初始化它?除了引入布尔标志并自己跟踪它之外。。 谢谢
我不熟悉匕首和莫基托。我尝试在单元测试中使用Dagger模块中定义的构造函数,以便使用默认值创建对象。 这是模块: @模块类自动关闭倒计时模块{ 这就是我在单元测试中模拟AutoCloseCountDown类的方法: @RunWith(MockitoJUnitRunner.class)公共类AutoCloseCountDownTimerTest{ 如何实现自动关闭的CountDownTimer将在
我正在尝试为我的navControl ler提供匕首柄。但是我使用的方法不起作用。我想提供navControl ler以便通过构造函数注入将其注入我的片段中。 我还创建了FragmentWorks类,以便通过构造函数注入我的依赖项。我知道是这里的问题,但我不知道正确的解决方案… 感谢您的帮助,谢谢! 原因:java.lang.ClassCastException:com.example.app。应