美文网首页
Dagger2 Activity子作用域多绑定

Dagger2 Activity子作用域多绑定

作者: 乌龟爱吃肉 | 来源:发表于2017-02-13 12:21 被阅读0次

    参考文章: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子作用域多绑定...成功将子作用域和父作用域解耦。

    相关文章

      网友评论

          本文标题:Dagger2 Activity子作用域多绑定

          本文链接:https://www.haomeiwen.com/subject/zibgittx.html