參考文章:http://frogermcs.github.io/activities-multibinding-in-dagger-2/
在上一篇文章中,我對Dagger生成的源碼進行了分析替蛉,順便自定義了一下作用域贯溅,分析了作用域的實現(xiàn)原理。但是對于上一篇中自定義作用域這一塊兒躲查,還是有些不妥的它浅。原因有二:
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);
}
}
}
現(xiàn)在腌乡,我們希望有一個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中創(chuàng)建塘装。因為這樣急迂,MainActivityComponent和SecondActivityComponent才能是AppComponent的SubComponents.
現(xiàn)在咱們可以注入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真正的實現(xiàn)就可以是下面這樣:
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);
}
}
上面就是所需的所有代碼。現(xiàn)在來看看實現(xiàn)原理阴幌,走一遍流程會對整個過程更加清晰勺阐。
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);
}
}
}
咱們所需的代碼大部分都在這個類了。
老規(guī)矩矛双,先來看看是怎么調(diào)用注入的渊抽。
@Override
protected void injectMembers(HasActivitySubcomponentBuilders hasActivitySubcomponentBuilders) {
((MainActivityComponent.Builder) hasActivitySubcomponentBuilders.getActivityComponentBuilder(MainActivity.class))
.activityModule(new MainActivityComponent.MainActivityModule(this))
.build()
.injectMembers(this);
}
此方法在BaseActivity中調(diào)用,傳入的hasActivitySubcomponentBuilders其實是Application(Application實現(xiàn)了HasActivitySubcomponentBuilders接口)议忽。調(diào)用Application的getActivityComponentBuilder方法懒闷,再把返回值強轉(zhuǎn)成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集合中取出來的愤估。嘿帮辟?這個集合哪來的?往上看就發(fā)現(xiàn)玩焰,這個集合是通過依賴注入注入進來的由驹。
咱們回到DaggerAppComponent中看一眼,在initialize初始化方法中發(fā)現(xiàn)這么一句:
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);
創(chuàng)建了Injector蒿赢,把Map傳給他润樱。在Injector里面就走注入那套流程。
好羡棵,回到調(diào)用上來:
((MainActivityComponent.Builder) hasActivitySubcomponentBuilders.getActivityComponentBuilder(MainActivity.class))
.activityModule(new MainActivityComponent.MainActivityModule(this))
.build()
.injectMembers(this);
現(xiàn)在我們知道壹若,傳一個MainActivity到getActivityComponentBuilder中,會從映射表中拿到MainActivity對應的ComponentBuilder返給我們皂冰。然后我們將它強轉(zhuǎn)為MainActivityComponent.Builder. 這個Builder也是一個接口店展,并且繼承自ActivityComponentBuilder:
@Subcomponent.Builder
interface Builder extends ActivityComponentBuilder<MainActivityModule, MainActivityComponent> {
}
MainActivityComponent的Module也是一個內(nèi)部類,也定義在MainActivityComponent中秃流。MainActivityComponentBuilder真正的實現(xiàn)也在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傳進去概说,然后調(diào)用build,build方法會創(chuàng)建一個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);
}
}
最后嚣伐,我們調(diào)用的是MainActivityComponentImpl的injectMembers的方法執(zhí)行注入糖赔。
以上就是解決開篇提到的兩個問題的方案:
1.Activity依賴于AppComponent,如果我們想要拿到Subcomponent轩端,就必須得先拿到AppComponent對象放典,還是挺心煩的。
2.AppComponent必須得為所有的Subcomponent定義Factory: MainActivityComponent plus(MainActivityComponent.ModuleImpl module);
老外管這個叫做Activities Subcomponents Multibinding, Activity子作用域多綁定...成功將子作用域和父作用域解耦基茵。