参考文章:http://frogermcs.github.io/activities-multibinding-in-dagger-2/
在上一篇文章中,我对Dagger生成的源码进行了分析,顺便自定义了一下作用域,分析了作用域的实现原理。但是对于上一篇中自定义作用域这一块儿,还是有些不妥的。原因有二:
1.Activity依赖于AppComponent,如果我们想要拿到Subcomponent,就必须得先拿到AppComponent对象,还是挺心烦的。
2.AppComponent必须得为所有的Subcomponent定义Factory: MainActivityComponent plus(MainActivityComponent.ModuleImpl module);
描述完了问题就来看看解决方案。从Dagger2.7开始,声明Subcomponent的父作用域有了新的方案。
首先,为所有的ActivityComponent的builder定义一个基本接口:
public interface ActivityComponentBuilder<M extends ActivityModule, C extends ActivityComponent> {
ActivityComponentBuilder<M, C> activityModule(M activityModule);
C build();
}
SubComponent可以是下面这样:
@ActivityScope
@Subcomponent(
modules = MainActivityComponent.MainActivityModule.class
)
public interface MainActivityComponent extends ActivityComponent<MainActivity> {
@Subcomponent.Builder
interface Builder extends ActivityComponentBuilder<MainActivityModule, MainActivityComponent> {
}
@Module
class MainActivityModule extends ActivityModule<MainActivity> {
MainActivityModule(MainActivity activity) {
super(activity);
}
}
}
现在,我们希望有一个SubComponents的builders的集合,这样我们在每个Activity中都可以获取到需要的builder。可以用Multibinding的特性。
@Module(
subcomponents = {
MainActivityComponent.class,
SecondActivityComponent.class
})
public abstract class ActivityBindingModule {
@Binds
@IntoMap
@ActivityKey(MainActivity.class)
public abstract ActivityComponentBuilder mainActivityComponentBuilder(MainActivityComponent.Builder impl);
@Binds
@IntoMap
@ActivityKey(SecondActivity.class)
public abstract ActivityComponentBuilder secondActivityComponentBuilder(SecondActivityComponent.Builder impl);
}
ActivityBindingModule在AppComponent中创建。因为这样,MainActivityComponent和SecondActivityComponent才能是AppComponent的SubComponents.
现在咱们可以注入SubComponent的builders的Map集合了:
public class MyApplication extends Application implements HasActivitySubcomponentBuilders {
@Inject
Map<Class<? extends Activity>, ActivityComponentBuilder> activityComponentBuilders;
private AppComponent appComponent;
public static HasActivitySubcomponentBuilders get(Context context) {
return ((HasActivitySubcomponentBuilders) context.getApplicationContext());
}
@Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.create();
appComponent.inject(this);
}
@Override
public ActivityComponentBuilder getActivityComponentBuilder(Class<? extends Activity> activityClass) {
return activityComponentBuilders.get(activityClass);
}
}
由于builders的Map集合没必要一定要注入到Application中,所以咱们有一个额外的抽象,HasActivitySubcomponentBuilders.
public interface HasActivitySubcomponentBuilders {
ActivityComponentBuilder getActivityComponentBuilder(Class<? extends Activity> activityClass);
}
最后,Activity真正的实现就可以是下面这样:
public class MainActivity extends BaseActivity {
//...
@Override
protected void injectMembers(HasActivitySubcomponentBuilders hasActivitySubcomponentBuilders) {
((MainActivityComponent.Builder) hasActivitySubcomponentBuilders.getActivityComponentBuilder(MainActivity.class))
.activityModule(new MainActivityComponent.MainActivityModule(this))
.build().injectMembers(this);
}
}
上面就是所需的所有代码。现在来看看实现原理,走一遍流程会对整个过程更加清晰。
DaggerAppComponent:
public final class DaggerAppComponent implements AppComponent {
private Provider<MainActivityComponent.Builder> mainActivityComponentBuilderProvider;
private Provider<ActivityComponentBuilder> mainActivityComponentBuilderProvider2;
private Provider<SecondActivityComponent.Builder> secondActivityComponentBuilderProvider;
private Provider<ActivityComponentBuilder> secondActivityComponentBuilderProvider2;
private Provider<Map<Class<? extends Activity>, Provider<ActivityComponentBuilder>>>
mapOfClassOfAndProviderOfActivityComponentBuilderProvider;
private MembersInjector<MyApplication> myApplicationMembersInjector;
private Provider<Utils> provideUtilsProvider;
private DaggerAppComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static AppComponent create() {
return builder().build();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.mainActivityComponentBuilderProvider =
new Factory<MainActivityComponent.Builder>() {
@Override
public MainActivityComponent.Builder get() {
return new MainActivityComponentBuilder();
}
};
this.mainActivityComponentBuilderProvider2 = (Provider) mainActivityComponentBuilderProvider;
this.secondActivityComponentBuilderProvider =
new Factory<SecondActivityComponent.Builder>() {
@Override
public SecondActivityComponent.Builder get() {
return new SecondActivityComponentBuilder();
}
};
this.secondActivityComponentBuilderProvider2 =
(Provider) secondActivityComponentBuilderProvider;
this.mapOfClassOfAndProviderOfActivityComponentBuilderProvider =
MapProviderFactory.<Class<? extends Activity>, ActivityComponentBuilder>builder(2)
.put(MainActivity.class, mainActivityComponentBuilderProvider2)
.put(SecondActivity.class, secondActivityComponentBuilderProvider2)
.build();
this.myApplicationMembersInjector =
MyApplication_MembersInjector.create(
mapOfClassOfAndProviderOfActivityComponentBuilderProvider);
this.provideUtilsProvider =
DoubleCheck.provider(AppModule_ProvideUtilsFactory.create(builder.appModule));
}
@Override
public MyApplication inject(MyApplication application) {
myApplicationMembersInjector.injectMembers(application);
return application;
}
public static final class Builder {
private AppModule appModule;
private Builder() {}
public AppComponent build() {
if (appModule == null) {
this.appModule = new AppModule();
}
return new DaggerAppComponent(this);
}
public Builder appModule(AppModule appModule) {
this.appModule = Preconditions.checkNotNull(appModule);
return this;
}
}
private final class MainActivityComponentBuilder implements MainActivityComponent.Builder {
private MainActivityComponent.MainActivityModule mainActivityModule;
@Override
public MainActivityComponent build() {
if (mainActivityModule == null) {
throw new IllegalStateException(
MainActivityComponent.MainActivityModule.class.getCanonicalName() + " must be set");
}
return new MainActivityComponentImpl(this);
}
@Override
public MainActivityComponentBuilder activityModule(
MainActivityComponent.MainActivityModule activityModule) {
this.mainActivityModule = Preconditions.checkNotNull(activityModule);
return this;
}
}
private final class MainActivityComponentImpl implements MainActivityComponent {
private Provider<MainActivity> provideActivityProvider;
private Provider<MainActivityPresenter> mainActivityPresenterProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private MainActivityComponentImpl(MainActivityComponentBuilder builder) {
assert builder != null;
initialize(builder);
}
@SuppressWarnings("unchecked")
private void initialize(final MainActivityComponentBuilder builder) {
this.provideActivityProvider =
DoubleCheck.provider(
ActivityModule_ProvideActivityFactory.create(builder.mainActivityModule));
this.mainActivityPresenterProvider =
DoubleCheck.provider(
MainActivityPresenter_Factory.create(
provideActivityProvider, DaggerAppComponent.this.provideUtilsProvider));
this.mainActivityMembersInjector =
MainActivity_MembersInjector.create(mainActivityPresenterProvider);
}
@Override
public void injectMembers(MainActivity arg0) {
mainActivityMembersInjector.injectMembers(arg0);
}
}
private final class SecondActivityComponentBuilder implements SecondActivityComponent.Builder {
private SecondActivityComponent.SecondActivityModule secondActivityModule;
@Override
public SecondActivityComponent build() {
if (secondActivityModule == null) {
throw new IllegalStateException(
SecondActivityComponent.SecondActivityModule.class.getCanonicalName() + " must be set");
}
return new SecondActivityComponentImpl(this);
}
@Override
public SecondActivityComponentBuilder activityModule(
SecondActivityComponent.SecondActivityModule activityModule) {
this.secondActivityModule = Preconditions.checkNotNull(activityModule);
return this;
}
}
private final class SecondActivityComponentImpl implements SecondActivityComponent {
private Provider<SecondActivity> provideActivityProvider;
private Provider<SecondActivityPresenter> secondActivityPresenterProvider;
private MembersInjector<SecondActivity> secondActivityMembersInjector;
private SecondActivityComponentImpl(SecondActivityComponentBuilder builder) {
assert builder != null;
initialize(builder);
}
@SuppressWarnings("unchecked")
private void initialize(final SecondActivityComponentBuilder builder) {
this.provideActivityProvider =
DoubleCheck.provider(
ActivityModule_ProvideActivityFactory.create(builder.secondActivityModule));
this.secondActivityPresenterProvider =
DoubleCheck.provider(SecondActivityPresenter_Factory.create(provideActivityProvider));
this.secondActivityMembersInjector =
SecondActivity_MembersInjector.create(secondActivityPresenterProvider);
}
@Override
public void injectMembers(SecondActivity arg0) {
secondActivityMembersInjector.injectMembers(arg0);
}
}
}
咱们所需的代码大部分都在这个类了。
老规矩,先来看看是怎么调用注入的。
@Override
protected void injectMembers(HasActivitySubcomponentBuilders hasActivitySubcomponentBuilders) {
((MainActivityComponent.Builder) hasActivitySubcomponentBuilders.getActivityComponentBuilder(MainActivity.class))
.activityModule(new MainActivityComponent.MainActivityModule(this))
.build()
.injectMembers(this);
}
此方法在BaseActivity中调用,传入的hasActivitySubcomponentBuilders其实是Application(Application实现了HasActivitySubcomponentBuilders接口)。调用Application的getActivityComponentBuilder方法,再把返回值强转成MainActivityBuilder类型。来看看Application类:
public class MyApplication extends Application implements HasActivitySubcomponentBuilders {
@Inject
Map<Class<? extends Activity>, Provider<ActivityComponentBuilder>> activityComponentBuilders;
private AppComponent appComponent;
public static HasActivitySubcomponentBuilders get(Context context) {
return ((HasActivitySubcomponentBuilders) context.getApplicationContext());
}
@Override
public void onCreate() {
super.onCreate();
appComponent = DaggerAppComponent.create();
appComponent.inject(this);
}
@Override
public ActivityComponentBuilder getActivityComponentBuilder(Class<? extends Activity> activityClass) {
return activityComponentBuilders.get(activityClass).get();
}
}
OK,Application的get方法返回一个ActivityComponentBuilder实例,是从activityComponentBuilders集合中取出来的。嘿?这个集合哪来的?往上看就发现,这个集合是通过依赖注入注入进来的。
咱们回到DaggerAppComponent中看一眼,在initialize初始化方法中发现这么一句:
this.mapOfClassOfAndProviderOfActivityComponentBuilderProvider =
MapProviderFactory.<Class<? extends Activity>, ActivityComponentBuilder>builder(2)
.put(MainActivity.class, mainActivityComponentBuilderProvider2)
.put(SecondActivity.class, secondActivityComponentBuilderProvider2)
.build();
变量名够直白了吧,这是一个ActivityComponentBuilder和Activity class的映射表。把MainActivity和SecondActivity以及他们相应的Provider放到了集合当中。这句后面就是:
this.myApplicationMembersInjector =
MyApplication_MembersInjector.create(
mapOfClassOfAndProviderOfActivityComponentBuilderProvider);
创建了Injector,把Map传给他。在Injector里面就走注入那套流程。
好,回到调用上来:
((MainActivityComponent.Builder) hasActivitySubcomponentBuilders.getActivityComponentBuilder(MainActivity.class))
.activityModule(new MainActivityComponent.MainActivityModule(this))
.build()
.injectMembers(this);
现在我们知道,传一个MainActivity到getActivityComponentBuilder中,会从映射表中拿到MainActivity对应的ComponentBuilder返给我们。然后我们将它强转为MainActivityComponent.Builder. 这个Builder也是一个接口,并且继承自ActivityComponentBuilder:
@Subcomponent.Builder
interface Builder extends ActivityComponentBuilder<MainActivityModule, MainActivityComponent> {
}
MainActivityComponent的Module也是一个内部类,也定义在MainActivityComponent中。MainActivityComponentBuilder真正的实现也在DaggerAppComponent中。
private final class MainActivityComponentBuilder implements MainActivityComponent.Builder {
private MainActivityComponent.MainActivityModule mainActivityModule;
@Override
public MainActivityComponent build() {
if (mainActivityModule == null) {
throw new IllegalStateException(
MainActivityComponent.MainActivityModule.class.getCanonicalName() + " must be set");
}
return new MainActivityComponentImpl(this);
}
@Override
public MainActivityComponentBuilder activityModule(
MainActivityComponent.MainActivityModule activityModule) {
this.mainActivityModule = Preconditions.checkNotNull(activityModule);
return this;
}
}
可以看到,咱们拿到了MainActivityComponent.Builder实例后,new一个MainActivityComponent.Module传进去,然后调用build,build方法会创建一个MainActivityComponentImpl实例并返回:
private final class MainActivityComponentImpl implements MainActivityComponent {
private Provider<MainActivity> provideActivityProvider;
private Provider<MainActivityPresenter> mainActivityPresenterProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private MainActivityComponentImpl(MainActivityComponentBuilder builder) {
assert builder != null;
initialize(builder);
}
@SuppressWarnings("unchecked")
private void initialize(final MainActivityComponentBuilder builder) {
this.provideActivityProvider =
DoubleCheck.provider(
ActivityModule_ProvideActivityFactory.create(builder.mainActivityModule));
this.mainActivityPresenterProvider =
DoubleCheck.provider(
MainActivityPresenter_Factory.create(
provideActivityProvider, DaggerAppComponent.this.provideUtilsProvider));
this.mainActivityMembersInjector =
MainActivity_MembersInjector.create(mainActivityPresenterProvider);
}
@Override
public void injectMembers(MainActivity arg0) {
mainActivityMembersInjector.injectMembers(arg0);
}
}
最后,我们调用的是MainActivityComponentImpl的injectMembers的方法执行注入。
以上就是解决开篇提到的两个问题的方案:
1.Activity依赖于AppComponent,如果我们想要拿到Subcomponent,就必须得先拿到AppComponent对象,还是挺心烦的。
2.AppComponent必须得为所有的Subcomponent定义Factory: MainActivityComponent plus(MainActivityComponent.ModuleImpl module);
老外管这个叫做Activities Subcomponents Multibinding, Activity子作用域多绑定...成功将子作用域和父作用域解耦。