Dagger2 Activity子作用域多绑定

参考文章: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 activityClass) {
        return activityComponentBuilders.get(activityClass);
    }
}

由于builders的Map集合没必要一定要注入到Application中,所以咱们有一个额外的抽象,HasActivitySubcomponentBuilders.

public interface HasActivitySubcomponentBuilders {
    ActivityComponentBuilder getActivityComponentBuilder(Class 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, Provider>>
      mapOfClassOfAndProviderOfActivityComponentBuilderProvider;

  private MembersInjector myApplicationMembersInjector;

  private Provider 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() {
          @Override
          public MainActivityComponent.Builder get() {
            return new MainActivityComponentBuilder();
          }
        };

    this.mainActivityComponentBuilderProvider2 = (Provider) mainActivityComponentBuilderProvider;

    this.secondActivityComponentBuilderProvider =
        new Factory() {
          @Override
          public SecondActivityComponent.Builder get() {
            return new SecondActivityComponentBuilder();
          }
        };

    this.secondActivityComponentBuilderProvider2 =
        (Provider) secondActivityComponentBuilderProvider;

    this.mapOfClassOfAndProviderOfActivityComponentBuilderProvider =
        MapProviderFactory., 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 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);
    }
  }

  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 provideActivityProvider;

    private Provider secondActivityPresenterProvider;

    private MembersInjector 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, 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 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子作用域多绑定...成功将子作用域和父作用域解耦。

你可能感兴趣的:(Dagger2 Activity子作用域多绑定)