Dagger2 Activity子作用域多綁定

參考文章: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子作用域多綁定...成功將子作用域和父作用域解耦基茵。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末奋构,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拱层,更是在濱河造成了極大的恐慌弥臼,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舱呻,死亡現(xiàn)場離奇詭異醋火,居然都是意外死亡悠汽,警方通過查閱死者的電腦和手機箱吕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門芥驳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人茬高,你說我怎么就攤上這事兆旬。” “怎么了怎栽?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵丽猬,是天一觀的道長。 經(jīng)常有香客問我熏瞄,道長脚祟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任强饮,我火速辦了婚禮由桌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘邮丰。我一直安慰自己行您,他們只是感情好,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布剪廉。 她就那樣靜靜地躺著娃循,像睡著了一般。 火紅的嫁衣襯著肌膚如雪斗蒋。 梳的紋絲不亂的頭發(fā)上捌斧,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音泉沾,去河邊找鬼骤星。 笑死,一個胖子當著我的面吹牛爆哑,可吹牛的內(nèi)容都是我干的洞难。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼揭朝,長吁一口氣:“原來是場噩夢啊……” “哼队贱!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起潭袱,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤柱嫌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后屯换,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體编丘,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡与学,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了嘉抓。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片索守。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖抑片,靈堂內(nèi)的尸體忽然破棺而出卵佛,到底是詐尸還是另有隱情,我是刑警寧澤敞斋,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布截汪,位于F島的核電站,受9級特大地震影響植捎,放射性物質(zhì)發(fā)生泄漏衙解。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一焰枢、第九天 我趴在偏房一處隱蔽的房頂上張望蚓峦。 院中可真熱鬧,春花似錦医咨、人聲如沸枫匾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽干茉。三九已至,卻和暖如春很泊,著一層夾襖步出監(jiān)牢的瞬間角虫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工委造, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留戳鹅,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓昏兆,卻偏偏與公主長得像枫虏,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子爬虱,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容