参考文章: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 {
ActivityComponentBuilder activityModule(M activityModule);
C build();
}
SubComponent可以是下面这样:
@ActivityScope
@Subcomponent(
modules = MainActivityComponent.MainActivityModule.class
)
public interface MainActivityComponent extends ActivityComponent {
@Subcomponent.Builder
interface Builder extends ActivityComponentBuilder {
}
@Module
class MainActivityModule extends ActivityModule {
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, 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 mainActivityComponentBuilderProvider;
private Provider mainActivityComponentBuilderProvider2;
private Provider secondActivityComponentBuilderProvider;
private Provider secondActivityComponentBuilderProvider2;
private Provider
咱们所需的代码大部分都在这个类了。
老规矩,先来看看是怎么调用注入的。
@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, Provider> 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., 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 {
}
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 provideActivityProvider;
private Provider mainActivityPresenterProvider;
private MembersInjector 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子作用域多绑定...成功将子作用域和父作用域解耦。