最后一篇介绍一下不同注入器Component之间的相互依赖,这个是什么意思呢。举个例子:B注入器要注入一个Context,因为Context是Android内部的类,所以只能在BModule类提供出来,这时候发现A注入器的AModule已经提供出Context,于是我们就可以B注入器和A注入器依赖在一起,B注入器就可以复用AModule的Context。
也就是说Component之间的依赖就是复用对方的Module。
dagger2为注入器之间的依赖提供了两种方式:
- @Component(modules = …, dependencies = …)
- @Subcomponent(modules = …)
下面结合一个例子来说明这两种方式:
通常我们会有这样一个场景,Activtiy需要使用 Application的Context,但是Activity无法获得这个Context,但是在另一个组件AppComponent里面的AppModule能提供,现在我们只需要让ActivityComponent组件依赖APPComponent就可以实现。
第一种方式
注意:1.两个依赖的组件的生命周期一定要不同,也就是用不同的@Scope修饰,或者是不修饰。
2.父组件必须暴露出子组件所需要的对象(重要要!!与第二种方法的区别(第二种方式不需要显示暴露出来),否则编译出错)
下面结合代码来说明:
//这里可以用@Scope来限定生命周期,也可以不修饰
@Component(modules = AppModule.class)
public interface AppComponent {
//必修暴露出Context
Context provideContext();
}
@Module
public class AppModule {
private Context appContext;
public AppModule(Context appContext) {
this.appContext = appContext;
}
//提供Context依赖
@Provides
public Context obtain() {
return appContext;
}
}
//这是Appliaction,将AppComponent 暴露出来
public class App extends Application {
private AppComponent appComponent;
@Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
}
public AppComponent getAppComponent() {
return appComponent;
}
}
//这里还是用@Component修饰,Component注解有一个参数dependencies,指定关联的另一个Component,这里是AppComponent。
//这样ActivityComponent就与AppComponent关联在一起,AppModule就可以为ActivityComponent提供依赖。
@Component(modules = ActivityModule.class, dependencies = AppComponent.class)
public interface ActivityComponent {
void inject(DaggerActivity daggerActivity);
}
这里ActivityModule为空实现,就不贴出代码了。
下面是DaggerActivity
public class DaggerActivity extends AppCompatActivity {
@Inject
Context context;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gui_view);
DaggerActivityComponent.builder().activityModule(new ActivityModule()).appComponent(getAppComponent()).build().inject(this);
}
private AppComponent getAppComponent() {
return ((App) getApplication()).getAppComponent();
}
}
注入方式为DaggerActivityComponent.builder().activityModule(new ActivityModule()).appComponent(getAppComponent()).build().inject(this);先创建DaggerActivityComponent的builder对象,再调用appComponent()传入一个AppComponent对象,最后build(),inject()。
那么appComponent()这个方法是怎么来的呢,这个是dagger2帮你生成的方法。
public final class DaggerActivityComponent implements ActivityComponent {
private Provider<Context> provideContextProvider;
private MembersInjector<DaggerActivity> daggerActivityMembersInjector;
private DaggerActivityComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
//初始化时调用builder.appComponent.provideContext()提供Context,并再次封装成Factory赋值给provideContextProvider。
//provideContextProvider 是DaggerActivityComponent的成员变量,它传给注入器初始化,在注入时就会将provideContextProvider里的Context提供出来。
private void initialize(final Builder builder) {
this.provideContextProvider = new Factory<Context>() {
@Override public Context get() {
Context provided = builder.appComponent.provideContext();
if (provided == null) {
throw new NullPointerException("Cannot return null from a non-@Nullable component method");
}
return provided;
}
};
this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), provideContextProvider);
}
@Override
public void inject(DaggerActivity daggerActivity) {
daggerActivityMembersInjector.injectMembers(daggerActivity);
}
public static final class Builder {
private ActivityModule activityModule;
private AppComponent appComponent;
private Builder() {
}
public ActivityComponent build() {
if (activityModule == null) {
this.activityModule = new ActivityModule();
}
if (appComponent == null) {
throw new IllegalStateException("appComponent must be set");
}
return new DaggerActivityComponent(this);
}
public Builder activityModule(ActivityModule activityModule) {
if (activityModule == null) {
throw new NullPointerException("activityModule");
}
this.activityModule = activityModule;
return this;
}
//此方法是dagger2自动生成的,将关联的Component添加进来,
作为builder的属性之一。
public Builder appComponent(AppComponent appComponent) {
if (appComponent == null) {
throw new NullPointerException("appComponent");
}
this.appComponent = appComponent;
return this;
}
}
}
所以本质上来讲就是让ActivityComponent实现类持有AppComponent实现类的引用,ActivityComponent实现类可以调用AppComponent实现类的属性和方法。
第二种方式
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
ActivityComponent plus(ActivityModule module);
}
//AppComponent的Module,里面能提供Context依赖
@Module
public class AppModule {
private Context appContext;
public AppModule(Context appContext) {
this.appContext = appContext;
}
@Provides
@Singleton
public Context obtain() {
return appContext;
}
}
//在Application注入
public class App extends Application {
private AppComponent appComponent;
@Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
}
//获得AppComponent
public AppComponent getAppComponent() {
return appComponent;
}
}
//注意这里用@Subcomponent而不是用@Component
@ActivityScope
@Subcomponent(modules = ActivityModule.class)
public interface ActivityComponent {
void inject(DaggerActivity daggerActivity);
}
这里ActivityModule为空实现,就不贴出代码了。
public class DaggerActivity extends AppCompatActivity {
//注入Context对象
@Inject
Context context;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_gui_view);
getAppComponent().plus(new ActivityModule()).inject(this);
}
private AppComponent getAppComponent() {
return ((App) getApplication()).getAppComponent();
}
}
这里首先在AppComponent接口里添加一个新的方法, ActivityComponent plus(ActivityModule module),必须是这种格式返回值是Component(用@Subcomponent修饰),参数必须Module类型或者不写参数,否则编译会出错。这里plus名字和inject名字一样,可以任取函数名,一般用plus。这个方法表示AcitivityComponent注入时可以从AppModule里找依赖。
通常是在Application里,将AppComponent暴露出来,
appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
public AppComponent getAppComponent() {
return appComponent;
}
在Activity时候注入,注入时写法如下
//这里就调用了plus方法与AppComponent关联
getAppComponent().plus(new ActivityModule()).inject(this);
private AppComponent getAppComponent() {
return ((App) getApplication()).getAppComponent();
}
这样在注入Activity 的 Context时候,就会从AppModule里面去找,因为ActivityModule没有Context依赖,也说明了这两个Component关联在一起了,可以复用AppModule的依赖。注意:如果两个Module都有Context,这时候必须用之前用过的@Named和@Qualifier两个注解去区分是哪一个Context,否则编译出错。
ActivityComponent plus(ActivityModule module) 这个方法的本质实质上是将ActivityComponent的实现类ActivityComponentImpl作为AppComponent的实现类DaggerAppComponent的子类。
public final class DaggerAppComponent implements AppComponent {
private Provider<Context> obtainProvider;
private DaggerAppComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
private void initialize(final Builder builder) {
this.obtainProvider = ScopedProvider.create(AppModule_ObtainFactory.create(builder.appModule));
}
//重写的plus方法,里面new ActivityComponentImpl()。
//如果plus有参数就传入module,new ActivityComponentImpl(module),无参数就new ActivityComponentImpl()。
@Override
public ActivityComponent plus(ActivityModule module) {
return new ActivityComponentImpl(module);
}
public static final class Builder {
private AppModule appModule;
private Builder() {
}
public AppComponent build() {
if (appModule == null) {
throw new IllegalStateException("appModule must be set");
}
return new DaggerAppComponent(this);
}
public Builder appModule(AppModule appModule) {
if (appModule == null) {
throw new NullPointerException("appModule");
}
this.appModule = appModule;
return this;
}
}
//内部类,持有外部类的this引用,因而可以直接调用外部类AppComponent的方法和属性
private final class ActivityComponentImpl implements ActivityComponent {
private final ActivityModule activityModule;
private MembersInjector<DaggerActivity> daggerActivityMembersInjector;
private ActivityComponentImpl(ActivityModule activityModule) {
if (activityModule == null) {
throw new NullPointerException();
}
this.activityModule = activityModule;
initialize();
}
//daggerActivityMembersInjector注入器的实现传入DaggerAppComponent.this.obtainProvider。
//obtainProvider就是外部类的Context依赖提供者,为Activity的注入提供了Context。
private void initialize() {
this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), DaggerAppComponent.this.obtainProvider);
}
//注入将Context注入进去
@Override
public void inject(DaggerActivity daggerActivity) {
daggerActivityMembersInjector.injectMembers(daggerActivity);
}
}
}
差不多了,断断续续把dagger2系列写完啦,大家看看就好,不喜勿喷。