聽說你又一次放棄了Dagger2,來聽老夫說道說道

關於Dagger2是啥,用法網上已經有很多了。不過聽說你已經很多次Dagger2從入門到放棄了,來來,讓我這個老中醫給你治一治。老夫手法純熟,不會讓你有任何痛苦的,放心讀下去吧。
本文同步自 博主的私人博客 wing的地方酒館

診斷

咳咳,看你這架勢病的不清,應該是陌生代碼恐懼症,你看看下面的代碼。會不會害怕。

private ShipDetailPresenter mShipDetailPresenter;   
mShipDetailPresenter = DaggerShipDetailComponent.builder()
        .shipDetailModule(new ShipDetailModule(this, this))
        .build()
        .inject();

喂!!!你怎麼跑了,快回來,還沒治病呢!!

用法回顧(注入第一式)

首先,對於一般來說,想創建一個對象,我們肯定採取new的形式:

mShipDetailPresenter = new ShipDetailPresenter(context,shipDetailView);

但是這樣耦合度較高,presenter的變化受限於Activity,也就是說假如我們的presenter的參數變成三個了,又要改Activity代碼。所以使用Dagger2的好處就很明顯了,如果改了構造器,只需要改對應的Module就可以。

@Module

上面提到了Module,這是什麼呢?其實這是一個提供參數的地方,將new Presenter所需要的參數,寫到這裏面來了。看示例代碼:

@Module //註解說明這是Module
public class ShipDetailModule {
  private ShipDeatilContract.View mView;
  private Context mContext;

  public ShipDetailModule(ShipDeatilContract.View mView, Context mContext) {
    this.mView = mView;
    this.mContext = mContext;
  }
    //註解說明Provide View 既提供View參數
  @Provides ShipDeatilContract.View getView(){
    return mView;
  }
    //註解說明Provide Context 既提供Context參數
  @Provides Context getContext(){
    return mContext;
  }
}

這是Module的寫法,就是把new Presenter(Context,View)寫到了裏面。

@Inject

Module怎麼知道presenter構造器需要幾個參數呢,答案是@Inject ,只需要在Presenter的構造器註解@Inject

public class ShipDetailPresenter implements ShipDeatilContract.Presenter {
  Context context;
  ShipDeatilContract.View shipDetailViewInterface;
  //告知構造求所需參數
  @Inject
  public ShipDetailPresenter(Context context,ShipDeatilContract.View shipDetailViewInterface){
    this.context=context;
    this.shipDetailViewInterface=shipDetailViewInterface;
  }

@Component

連接Presenter和Module的東東,我們只需要寫一個接口,來返回Presenter對象,Dagger2就會自動生成對應的對象給我們。

//註解標註Component  並且告知需要的module是什麼
@Component(modules = ShipDetailModule.class)

public interface ShipDetailComponent {
    //接口的方法,返回presenter
  ShipDetailPresenter inject();

}

最終聯繫

現在看回第一段代碼

   private ShipDetailPresenter mShipDetailPresenter;   
   mShipDetailPresenter = DaggerShipDetailComponent.builder()
        .shipDetailModule(new ShipDetailModule(this, this))
        .build()
        .inject();

DaggerShipDetailComponent這個類是build之後Dagger2自動爲我們生成的類,查看源碼它實現了ShipDetialComponent這個方法,所以inject()函數自然會爲我們返回一個presenter來啦。

用法回顧(注入第二式)

你可能犯嘀咕了,你這種寫法不科學!跟我看到的不一樣。咳咳,不要急,老夫再給你說另一種用法。這種方法的代碼如下:

 @Inject ShipDetailPresenter mShipDetailPresenter;   
   DaggerShipDetailComponent.builder()
        .shipDetailModule(new ShipDetailModule(this, this))
        .build()
        .inject(this);

對應的Component爲:

public interface ShipDetailComponent {

  void inject(ShipDetailActivity);

}

其他的寫法都一樣。 此時你心裏肯定犯嘀咕了,麼麼的,你剛纔說是inject()返回presenter所以可以賦值,這個void你怎麼解釋! 是不是又要放棄拉,年輕人,不要輕言放棄,聽老夫一言。

想要知道Dagger2 怎麼做的那麼神奇,必須知道他的原理,原理怎麼看?當然是看他生成的代碼唄!

Dagger2原理

第一式解密

首先看第一種方法的原理,找到DaggerShipDetailComponent 發現代碼如下:

public final class DaggerShipDetailComponent implements ShipDetailComponent {
  private Provider<Context> getContextProvider;

  private Provider<ShipDeatilContract.View> getViewProvider;

  private Provider<ShipDetailPresenter> shipDetailPresenterProvider;
  /** 去處多行代碼**/
}

可以看到Component確實實現了我們定義的Component,所以他的inject()方法肯定是返回了一個presenter

@Override
  public ShipDetailPresenter inject() {
    return shipDetailPresenterProvider.get();
  }

老夫沒有騙你吧,至於這個provider如何拿到的newPresenter,這裏給你留個家庭作業。現在應該有些頭緒了吧,Dagger2沒有想象中那麼難,對不對?接下來看看讓你懵逼的第二式。

第二式

直接看生成的代碼!在DaggerShipDetailComponent發現了

 public void inject(ShipDetailActivity activity) {
    shipDetailsMembersInjector.injectMembers(activity);
  }

繼續往下看,看到了一個init方法

private void initialize(final Builder builder) {

    this.getContextProvider = ShipDetailModule_GetContextFactory.create(builder.shipDetailModule);

    this.getViewProvider = ShipDetailModule_GetViewFactory.create(builder.shipDetailModule);
//工廠生成provider 用來提供presenter
    this.shipDetailPresenterProvider =
        ShipDetailPresenter_Factory.create(getContextProvider, getViewProvider);
//生成MembersInjector
    this.shipDetailActivityMembersInjector =

      ShipDetailActivity_MembersInjector.create(shipDetailPresenterProvider);
  }

接下來順藤摸瓜,找到了ShipDetailActivity_MembersInjector,只看關鍵部分源碼


public final class ShipDetailActivity_MembersInjector
    implements MembersInjector<ShipDetailActivity> {

//進行注入操作
  public static void injectShipDetailPresenter(
      ShipDetailActivity instance, Provider<ShipDetailPresenter> shipDetailPresenterProvider) {
    instance.shipDetailPresenter = shipDetailPresenterProvider.get();
  }
}

相信聰明的你已經明白了,爲什麼返回void還能注入,不知道你有沒有發現,第二式的presenter沒有用private修飾,在injectShipDetailPresenter(ShipDetailActivity,Provider)的時候將 activity.presenter = Proivider.get()!

如果讓我用兩個字來形容的話,我只能說

太他媽精彩

嘛,這次會診就到這裏吧,回家記得勤加鍛鍊,早日康復,再見。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章