Android 經常使用開源框架源碼解析 系列 (九)dagger2 呆哥兔 依賴注入庫

1、前言
依賴注入定義
    目標類中所依賴的其餘的類的初始化過程,不是經過手動編碼的方式建立的。
是將其餘的類已經初始化好的實例自動注入的目標類中。
 
「依賴注入」也是面向對象編程的 設計模式 ————-組合的配套使用
做用 :下降程序的耦合,耦合就是由於類之間的依賴關係所引發的
產生場景:在一個對象裏去建立另外一個對象的實例
問題:過多的類,對象之間的依賴會形成代碼難以維護。
 
不符合開閉原則的對象的引用寫法:錯誤示例:
    public class ClassA {
        classB b ;
        public ClassA (ClassB b ){
            this.b = b;
        }
    }
 
經過依賴注入的方式 ,將ClassB對象注入到ClassA中。從而靈活配置ClassA 的屬性
    public class ClassA{
        @Inject
        ClassB b;
        public ClassA(){...}
    }
 
常見的四種注入方式
   一、接口注入
         定義ClassBInterface接口,在其內定義setB()函數.ClassAInterface去實現ClassBInterface 接口,在ClassAInterface類中定義了一個ClassBInterface成員變量,並複寫setB()函數,最終經過setB()函數完成接口注入操做。
    
        public interface ClassBInterface {
            void setB(ClassB b);
        }
        public class ClassA implements ClassBInterface {
            ClassB classB;
            @Override
            public void setB(ClassB b) {
                classB = b;
            }
        }
 
    二、set注入——依賴注入的(核心:外部傳遞而來)重要方法之一
   public class ClassAset {
        ClassB classb;//定義成員變量
        //經過set方法完成注入(對其成員變量的賦值),更加剝離了各個部分的耦合性
            public void setCalssB(ClassB b){
                classb =b;
            }
    }    
 
ps:不少時候都是經過
    三、經過構造方法注入-經常使用
    public class ClassAConstructor {
       //在classA中定義一個ClassB 成員變量
        ClassB classB;
 
        //將ClassB做爲參數,傳遞至ClassA的構造函數中,進行成員變量ClassB的賦值
        public ClassAConstructor(ClassB b){
            classB = b;
        }
    }
    
   四、經過Java依賴註解完成方法注入-重點
/**
* 對象的組合-在一個類中引用其餘對象,容器依賴持有的類的實現
* */
public class FruitContainer {
    //在FruitContainer類中持有了Banana的引用,從而調用引用類的方法完成某些功能
    Banana banana;
    //在FruitContainer的構造方法中經過banana構造方法新建了一個banana對象
    public FruitContainer(){
       banana =new Banana();
    }
}                          
涉及場景:業務需求改變,被持有的類的構造方法進行了改變,那麼持有這個類的不少類都有可能須要進行不一樣長度的改變,形成了代碼的很大的耦合性增長,下降了擴展性,是種比較嚴重的不符合開閉原則的寫法
 
思考: 在FruitContainer依賴Banana的實現的狀況下,用什麼辦法在不修改FruitContainer的類狀況下,知足Banana或是其內在的構造函數進行了修改。
答: 經過註解的方式 ,注入到宿主類:FruitContainer 類中
 
public class FruitConainerInject{//類不用關心具體(水果)引用類的實現
    添加@Inject,自動完成注入功能————> 這時候並不會完成注入,須要引入註解庫並在目標類中調用才完成注入
    Fruit f;
    public FruitContainerInject(){
    //動態注入
    }
}
 
小結:
不要在須要依賴的類中經過new 類建立依賴而是經過方法提供的參數注入進來
 
2、dagger2的使用流程
    一、將須要注入的對象的類的構造參數使用@Inject標註,在編譯的時候編譯器會通知dagger2 實例化該類
    二、新建component接口,並在開始使用@Component註解進行註釋,自定義void inject()函數,並傳入須要依賴注入的對象的類型
    三、使用編譯器的make project 功能 ,進行編譯,在build文件夾內目錄下生成Component所對應的類,生成的類的名字格式爲「Dagger+自定義的Component名字」
    四、在須要注入的目標類(通常是Activity or Fragment之類)中,使用@Inject標註要注入的變量,在初始化時候調用自動生成的Component類的builder().xxModule(xxx).build().自定義inject()方法,完成構建
 
3、dagger2的基本用法
0、導入
    compileOnly 'org.glassfish:javax.annotation:10.0-b28'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.5'
    implementation 'com.google.dagger:dagger:2.5’
 
導入可能存在的問題:
Error:Could not get unknown property 'classpath' for task ':app:transformJackWithJackForDebug' of type com.android.build…..
 
  • 1. 刪除project根目錄build.gradle中的: classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8’ (通常如今都沒有)
  • 2.app的build.gradle中,刪除apply plugin 'android-apt'
  • 3.在app的build.gradle中,dependencies中的 apt 'com.google.dagger:dagger-compiler:2.1.0' 改成 
  • annotationProcessor 'com.google.dagger:dagger-compiler:2.1.0'
 
 
一、@Inject 註解
    一、標記在須要依賴的變量,dagger2爲其提供依賴,並實例化有此註解的類
    二、使用在構造函數上,構造函數工廠,經過標記構造函數讓dagger2 使用,從而提供相關的依賴
ps:dagger2 經過@Inject標記能夠在須要這個類實例的時候,來找到這個構造方法,將相關的實例new出來
 
    (1)、@Inject標記的變量 
經過@Inject 標記的變量 ,在make project後會在其build下的source文件夾內的debug,包名下生成:
"類名_MembersInjector」文件
@Override
public void injectMembers(Car instance) {
  if (instance == null) {
    throw new NullPointerException("Cannot inject members into a null reference");
  }
//經過調用typeProvider.get()函數獲取到.type ,在這裏type 是經過inject標註的
  instance.tyre = tyreProvider.get();
}
ps:經過@Inject 標記的成員變量不能被命名爲private 屬性,不然沒法獲取到
 
 
(2)、@Inject標記的構造方法
經過@Inject 標記的構造方法 ,在make project後會在其build下的source文件夾內的debug,包名下生成:
"類名_Factory」文件
INSTANCE;
@Override
public Tyre get() {
  return new Tyre();
}
public static Factory<Tyre> create() {
  return INSTANCE;
}
 
依賴注入是依賴的對象實例————>須要注入的實例屬性
新建工廠實例並調用成員屬性注入類完成Tyre的實例注入
 
 
二、@Component 註解——注入者與被注入者之間的牆梁,more Improtant
用於標註接口 或是 抽象類,能夠完成依賴注入的過程。
將@Inject 和@Module 聯繫起來的牆梁,從@Module中獲取依賴並將依賴注入給 @Inject
@Component標記的接口或是抽象類,在make project後會在其build下的source文件夾內的debug,包名下生成:
"Dagger接口名稱」文件
 
@Component
public interfaceCarComponent {
/**一、參數必須是須要注入依賴的類型,不能是其父類 or 子類
*二、注入接口的方法的返回值 必須是void,命名能夠任意可是最好是inject+須要注入依賴的類名,便於識別
**/
    voidinjectCar(Car car);  <——————將依賴注入到的目標位置
}
 
private MembersInjector<Car> carMembersInjector;
private void initialize(final Builder builder) {
//經過carMembersInjector查找目標類對應的成員屬性注入類,將依賴的屬性的工廠實例傳入給注入類,完成依賴注入
  this.carMembersInjector = Car_MembersInjector.create(Tyre_Factory.create());
}
 
public Car() {
    //經過Component如下方法注入car 屬性,整個流程
    DaggerCarComponent.builder().build().injectCar(this);
}
 
    標記了@Inject 的變量,須要配套對其對象的構造方法 進行@Inject的構造方法標記 來肯定用何種構造方法完成對象的構建,才能建立完成。最後在構建好的使用了@Component修飾的接口中,在目標類的構造方法中使用Component的builder()方法調用接口中的方法完成整個方法的構建
 
4、dagger2的源碼
DaggerCarComponent.builder().build().injectCar(this); 經過構建者模式完成建立
 
在build() 方法中完成了DaggerCarComponent 對象的建立:
public CarComponent build() {
  return new DaggerCarComponent(this);
}
 
private void initialize(final Builder builder) {
//調用成員注入器Car_MembersInjector 經過create方法完成carMembersInjector對象的構建
  this.carMembersInjector = Car_MembersInjector.create(Tyre_Factory.create());
}
 
injectCar():完成實際的成員變量的注入
@Override
public void injectCar(Car car) {
  carMembersInjector.injectMembers(car);
}
 
injectMembers():在 xx_Factory下完成對象的建立
@Override
public void injectMembers(Car instance) {
  if (instance == null) {
    throw new NullPointerException("Cannot inject members into a null reference");
  }
    //最後經過tyreProvider.get()函數完成注入
  instance.tyre = tyreProvider.get();
}
 
5、dagger2的經常使用註解-區別於@Inject
 
思考:如何須要提供的類構造函數沒法修改怎麼辦?好比引用庫 裏面的類 沒法修改如何解決?
 
@Module 註解
  •  能夠給不能修改的類提供依賴,dagger2 會在該類中尋找實例化某個類所須要的依賴
  • 但須要配合@Provide 註解一塊兒使用
 
@Provides 
  • 標註一個Module中的方法,可使須要提供依賴的時候被調用。
  • 同時,被@Provides註解修飾的方法他的返回值就是依賴對象的實例。
 
ps:@Provides註解只能使用在Module當中
 
一、建立一個用@Module修飾的目標類,和一個@Provides修飾的構建類
@Module
public class CarModule {
//在須要提供依賴的時候被調用
    @Provides
    static Car provideCar(){
        return new Car();
    }
}
 
二、在component 橋樑類裏指明modules對應的類字節碼對象,是具體哪一個module
@Component(modules = CarModule.class)
public interface CarComponent {
    void injectCar(Car car);
}
 
三、make program 後生成 :「CarModule_ProvideCarFactory」
在其內部調用了Module的內部方法函數 建立car對象
@Override
public Car get() {
  return Preconditions.checkNotNull(
      CarModule.provideCar(), "Cannot return null from a non-@Nullable @Provides method");
}
 
通常依賴注入的初始化使用方法:
xxxComponent
        .builder()
        .xxxModule(new xxxModule(
                view:this, new xxx實現InteractorImpl() ) )
        .build()
        .inject(activity:this);
ps:
  • InteractorImpl()是P層 被@Inject的標註方法;
  • 同時 P層的對象 也是被@Inject 標記註解
  • 將Module層 標記爲@Module註解
  • 根據須要標註 M層內的方法 @Provieds
  • 添加@Component(modules = xx.class)註解,並在其內定義一個inject(傳入xxActivity的Activity對象)函數
 
 
ps:經過provide註解 ,dagger2 會找到被標記了@Provides註解的方法,並調用其構造方法來完成對象的建立
 
6、dagger2的補充知識
    同ButterKnife 依賴注入框架同樣 dagger2也是採用了apt代碼自動生成技術,註解停留在編譯時,不影響性能。
    在編譯器build 過程當中,APT 也就是dagger-compiler 掃描到註解生成對應的class字節碼文件好比掃描到@Provide
就會生成對應的 provide_factory ,來再須要被初始化的時候查找響應的構造方法。
 
    (一) 一些經常使用的dagger2的使用
       一、帶一個參數的構造參數
    示例:    
      public class Product(){
           @Inject
            public product(){}
        }
    public class Factory{
        Product product;
       @Inject
        public Factory(Product product){
            this.product = product;
        }
    }
解析:在 xxActivity 中進行 inject() 的時候,發現 Factory 的構造函數被 @Inject 標註了且帶有一個參數,而後 dagger2 就去尋找 Product 發現它的構造函數也被 @Inject 標註而且無參數,因而 dagger2 把 Product 的實例注入給 xxActivity,而後再去實例化 Factory 的時候用的是已經注入給 xxActivity 的那個 Product 實例。也就是說咱們能夠這樣理解:並非 Factory 直接實例化 Product,而是 xxActivity 實例化 Product 後交給 Factory 使用的。
 
   二、帶Module的Inject方式
以第三方庫爲OkHttp爲例:直接上修改後的代碼
       @Module
        public class HttpActivityModule{
            @Provides
            OkHttpClient provideOkHttpClient(){
                return new OkHttpClient();
            }
        }
        @Component (modules =HttpActivityModule.class)
    public interface HttpActivityComponent{
        void inject(HttpActivity httpActivity);
    }
 
    三、帶複雜 Module的Inject方式
使用場景:
    在使用dagger2的時候傳入一些配置,直接使用module的構造參數傳入便可。實例化的時候使用的是builder內部類傳入須要的值。
    Module中其中一個依賴又要依賴另一個依賴。若是被@Provides標註的方法帶有參數,dagger2會自動尋找本Module中其餘返回值類型爲參數的類型的且被@Provides標註的方法。
       @Module
        public class HttpActivityModule{
            private int txtSize;
                public HttpActivityModule(int txtSize){
                        this.txtSize = txtSize;
                }
                @Provides
            OkHttpClient provideOkHttpClient(){
                    OkHttpClient client = new OkHttpClient();
                        client.setTxtSize(this.txtSize);
                        return client;
                  }
                @Provides
                RetrofitManager provideRetrofitManager( OkHttpClient client){
                    return new RetrofitManager(client);————return new 誰就在Activity中 @Inject誰
                        }
            }
若是本Module中找不到就會去看這個類的構造參數是否被@Inject標註:
    public class OkHttpClient {
        private int txtSize;
        @Inject
        public OkHttpClient(){}
    }
     @Module
        public class HttpActivityModule{
            private int txtSize;
            public HttpActivityModule(int txtSize){
                    this.txtSize = txtSize;
            }
              ...
                @Provides
                RetrofitManager provideRetrofitManager( OkHttpClient client){
                    return new RetrofitManager(client);————return new 誰就在Activity中 @Inject誰
                }
    四、Component 依賴Component 模式
    有時候一個Component 跟另一個Component 所提供的依賴有重複的時候,這時候能夠像操做extends關鍵字同樣進行依賴關係的注入
 
    a、dependence 方式 
   
        @Component(modules = HttpActivityModule.class)
         public interface HttpActivityComponent{
            RetrofitManager provideRetrofitManager();
        }
    
        @Component(dependences =HttpActivityComponent.class)
        public interface HttpFragmentComponent{
           void inject(HttpFragment httpFragment);
        }
   在Activity中的關鍵代碼:
        private HttpActivityComponent httpActivityComponent;//實例化component對象
            在onCreate()中:
                httpActivityComponent = DaggerHttpActivityComponent.builder().        
                        .httpActivityModule( new HttpActivityModule (this) )
                        .build();
 
        public HttpActivityComponent getHttpActivityComponent(){
            return httpActivityComponent;
        }
 
    在對應的fragment中的關鍵代碼:
       @Inject
        RetrofitManager retrofitManager;
 
            在onViewCreated()中關鍵代碼:
                HttpActivityComponent activityComponent=((HttpActivity) getActivity()).getHttpActivityComponent();
               DaggerHttpFragmentCompent
                            .builder()
                            .httpActivityComponent(activityComponent)
                            .build()
                            .inject(this);
小結:
    一、在父Component中要顯示的寫出須要暴露可提供給子Component的依賴 
    二、在子Component的註解中使用 :(dependences =父類Component.class)
   三、在子Component的實例化   void inject(xxx)
 
 
    b、subComponent 方式 
部分代碼同a方式同樣進行省略操做,展現不一樣地方:  
     @Component(modules = HttpActivityModule.class)
         public interface HttpActivityComponent{
           HttpFragmentComponent httpFragmentComponent();
        }
    
        @SubComponent -真實實現inject()
        public interface HttpFragmentComponent{
           void inject(HttpFragment httpFragment);
        }
 
 在對應的fragment中的關鍵代碼:
      HttpActivityComponent activityComponent=
                        ((HttpActivity) getActivity()).getHttpActivityComponent()
                             .httpFragmentComponent().inject(this);
             
   subComponent 實現方式總結
        一、先定義子Component,使用@SubComponent標註
        二、定義父Component,在其中定義獲取子Component的方法
        三、注意子Component 實例化方式
 
思考:若是子Component構建時候不是無參的而是有參數的狀況,又該如何進行處理呢?
 
    解析重點:子Component構建時候傳入參數的話,就須要在Component中使用@Subcomponent.Builder註解(接口or抽象類) 
 
示例:
    父Component:
        @Component( modules = {AppModule.class})
        public interface AppComponent{
            XxActivityComponent.XxBuilderxxBuiler();
        }
 
    子Component:
    @Subcomponent ( modules = {XxActivityModule.class})
    public interface XxActivityComponent{
        void inject( XxActivity activity);
 
           @Subcomponent.Builder
            interface XxBuilder{
                XxBuilder xxActivityModule(XxActivityModile module);
                   XxActivityComponent build();
            }
    }
Module 類:
    @Module 
    public class AppModule{
        @Provides
        AppBen provideAppBean(){
            return new AppBean():
        }
 
    @Module 
    public class XxActivityModule{
        private ActivityBean activityBean;
        public XxActivityModule (ActivityBean bean){
            this.activityBean = bean;
        }
        @Provides 
        ActivityBean provideActivityBean(){
            return this.activityBean;
        }
    }        
      而後看一下在其對應的Application 和Activity 裏的實現      
        App extends Application{ //applicaation 對應了父Component
            private AppComponent appComponent;
                @Override 
                public void onCreate(){
                    appcComponent= DaggerAppComponent.create();
                }
                public AppComponent getAppComponent(){
                    return appComponent;
                }
        }
 
    XxActivity extends AppCompatActivity{
            @Inject 
            AppBean appBean;
            @Inject 
            ActivityBean activityBean;
            …
          ...  onCreate(){
                …
                ((App)getApplication() ) .getAppComponent()
                    .xxBuilder()
                    .xxActivityModule (new XxActivityModule (new ActivityBean() ) )
                    .build()
                    .inject (this);
                …
        }
    小結:
        subComponent 實現方式小結:
        一、在子Compoonent ,定義一個藉口或是抽象類(一般定義爲xxBuilder),使用@Subcomponent.Builder() 標註
        二、編寫返回值 爲XxBuilder,方法的參數須要傳入參數的XxModule類型
        三、編寫返回值爲當前子Component 的無參方法
        四、 父Component 中定義獲取子 Component.Builder的方法
 
(二) dagger2 中有關Scope 做用域
    一、無module 的狀態
        只須要提供依賴的類,以及Component 都添加@Singleton標註
        @Singleton
        public class Product {
            @Inject
            public Product(){}
        }    
        @Singleton
        @Component
        public interface Factory{
            void inject(xxActivity activity);
        }
        在使用的時候,在對應的Activity裏進行聲明:
        @Inject
        Product product;
        DaggerXxActivityComponent.create().inject)the);
ps:
若是使用@Singleton 標註了構造參數 ,或是隻標註了提供依賴的類 並無標註Component類 那麼 系統會報如下兩種錯誤:
    @Scope annotations are not allowed on @Inject  constructors.Annotate the class instead
    @包名 .xxComponent (unscoped) may not reference…@Singleton class ….
 
 
二、有module 的狀態
         Component 必須添加@Singleton 標註,再根據須要給Module中的@Provides標註的方法再標註上@Singleton 
        //無參數構造方法
       public class Product{
        public Product(){}
        }
        //Component 接口類:
        @Singleton
        @Component (modules = XxActivityModule.class)
        public interface XxActivityComponent{
            void inject(XxActivity activity);
        }    
    
@Module
    public class XxActivityModule{
        @Singleton
        @Provides
            Product provideProduct(){
                return new Product():
            }
    }
   
有關Scope 的注意事項:
    一、把Scope簡單的解釋爲單例是不科學的。正確的理解應該是:
        在某個範圍裏他是單例(何爲做用域呢?能夠看做是程序中實例化的Component 的生命週期的長短;
        若是在Application裏 build的那它的做用域就是整個App的生命週期;
        若是在Activity中build的那它的做用域就隨着Activity的生命週期保持一致;
        )         
    二、Scope 只是一個標註 ,只跟它使用的地方及Component實例化的地方有關
    三、在Component 依賴Component 的時候,Scope的名字必須不一樣。
 
 
 
7、dagger2 結合 MVP 模式的小示例片斷詳解
在普通模式下 使用MVP 模型,P層 和V層 也就是Activity會相互持有對方的引用,以下:
 
View層 實例代碼:
public class PopActivity extends AppCompatActivity implements xxViewImpl {
    private xxPresenter xxxPresenter;
@Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
            ...
        //實例化p層對象,將View傳遞給P對象,並調用P層方法
        xxxPresenter = new xxPresenter(this);
        xxxPresenter.xxx();
    }
}
Presenter層實例代碼:
public class xxPresenter {
    //View層的引用
    private xxViewImpl mView;
 
    public xxPresenter(xxViewImpl view) {
        mView = view;
    }
    public void xxx(){
        //調用model數據層方法,加載數據
        ...
        //回調方法在成功 or 失敗時候
        mView.updateUi();
    }
}
以上實例代碼就存在Activity和Presenter 存在必定的耦合程度,若是使用依賴注入的形式的話:
 
 
View層僞代碼:
public class xxActivity extends  AppCompatActivity implements xxViewImpl{
    @Inject 
    xxPresenter xxxPresenter; 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ...
        //依賴注入框架初始化
        DaggerXXComponent.builder()
                    .XXModule(new XXModule(this))
                .build()
                .inject(this);
        //調用p層方法
        xxxPresenter.xx*();
    }
}
tips:代表xxPresenter是須要注入到這個Activity中,即代表這個Activity依賴於xxPresenter,可是p對象不能爲private修飾符。這裏經過new XXModule(this)將view傳遞到XXModule裏,而後XXModule裏的provideXXView()方法返回這個View,當去實例化XXPresenter時,發現構造函數有個參數,此時會在Module裏查找提供這個依賴的方法,將該View傳遞進去,這樣就完成了presenter裏View的注入。
 
P層僞代碼:
public class xxPresenter {
    //View層的引用
     xxViewImpl mView;
     
     @Inject
    public xxPresenter(xxViewImpl view) {
        mView = view;
    }
    public void xxx(){
        //調用model數據層方法,加載數據
        ...
        //回調方法在成功 or 失敗時候
        mView.updateUi();
    }
}
tips:在P層構造方法添加@Inject註解,代表這個構造方法與Activity中的p層對象創建聯繫。也就說檔某個類被@Inject,就會到這個類中的構造方法中,查找從而完成依賴注入。
注意⚠️:google不推薦直接將P層的構造參數添加註解,更加推薦將P層放到Module裏進行管理,由於這樣代碼更加容易管理。
 
新建用於連接的牆梁接口
   @Component(modules=XXModule.class )
public interface XXComponent{
    void inject(xxActivity activity);
}
tips:根據Component將前面兩項創建聯繫,並自定義void 返回類型的方法傳入須要被注入的類Activity。並進行build項目
 
@Module註解的僞代碼:
@Module
public class XXModule {
    final xxViewImpl mView;
 
    public XXModule(xxViewImpl view) {
        mview = view;
    }
    @Provides
    XXView provideXXVIew(){
        return mView;
    }
}
tips:用來提供依賴,來使得部分沒有構造函數的類的依賴,也就是沒法手動@Inject的類好比引用庫,系統庫;
    在module類裏,在構造方法裏將外界傳進來的view賦值給聲明的成員對象,並經過@Provides註解標註,以providexx開頭名稱,並返回聲明的view對象,該方法是爲了提供依賴,能夠建立多個不一樣的方法提供不一樣依賴
 
 
下面經過僞代碼實例再研究下其原理性的內容:
 
    在對已經@Inject 修飾過的構造方法進行makeProgram 過程後,會生成xxx_Factory類:
    
  public XXPresenter_Factory(Provider<xxViewImpl> viewProvider) {
    assert viewProvider != null;
    this.viewProvider = viewProvider;
  }
  @Override
  public xxPresenter get() {
    return new xxPresenter(viewProvider.get());
  }
  public static Factory<XXPresenter> create(Provider<XXViewImplw> viewProvider) {
    return new XXPresenter_Factory(viewProvider);
  }
     能夠看到參數是一個Provider類型,範型參數是View層 ,經過構造方法對viewProvider進行實例化。成員參數沒有直接用xxViewImpl 而經過Provider類型修飾是由於前者是一個依賴,而依賴提供者是XXModule,所以這個viewProvider也是由XXModule提供的
    下面的get()函數內,也能夠看到,在這裏實例化了xxPresenter對象 經過new xxPresenter(依賴的xxViewImpl,只是是經過get()函數獲取的)
    最後經過create()函數,將含有一個參數viewProvider用來建立 XXPresenter_Factory類
 
接下來再來看一下,XXModule類對應的注入類
public final class XXModule_ProvideMainViewFactory implements Factory<xxViewImpl> {
  private final XXModule module;
  public XXModule_ProvideXXViewFactory(XXModule module) {
    assert module != null;
    this.module = module;
  }
 
  @Override
  public xxViewImpl get() {
    return Preconditions.checkNotNull(
        module.provideXXView(), "Cannot return null from a non-@Nullable @Provides method");
  }
 
  public static Factory<xxViewImpl> create(XXModule module) {
    return new XXModule_ProvideXXViewFactory(module);
  }
}
    在Module類中被@Provides修飾的方法都會對應的生成一個工廠類。這裏是XXModule_ProvideXXViewFactory,
咱們看到這個類裏有一個get()方法,其中調用了XXModule裏的provideXXView()方法來返回咱們所須要的依賴xxViewImpl。還記得在xxPresenter_Factory裏的get()方法中,實例化XXPresenter時候的參數viewProvider.get()嗎?到這裏咱們就明白了,原來那個viewProvider就是生成的XXModule_ProvideXXViewFactory,而後調用了其get()方法,將咱們須要的xxViewImpl注入到XXPresenter裏。
 
思考:xxPresenter_Factory的建立是由create()完成的,可是這個create是在什麼位置調用的?
答案顯而易見確定是在橋樑類Component 注入類中完成的。
    示例僞代碼:
public final class DaggerXXComponent implements XXComponent {
  private Provider<xxViewImpl> provideXXViewProvider;
  private Provider<XXPresenter> XXPresenterProvider;
  private MembersInjector<XXActivity> XXActivityMembersInjector;
 
 
  private DaggerXXComponent(Builder builder) {
    assert builder != null;
    initialize(builder);
  }
  public static Builder builder() {
    return new Builder();
  }
     
   在initialize()函數中,能夠看到三個create()方法,每個provider工廠都對應一個providerFactory.craete()實例,將providerXXViewProvider做爲參數傳遞給XXPresenterProvider,後又又做爲參數傳遞給Activity的注入類:XXActivityMembersInjector對象進行實例化。
  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {
    this.provideXXViewProvider = XXModule_ProvideXXViewFactory.create(builder.XXModule);
    this.XXPresenterProvider = XXPresenter_Factory.create(provideXXViewProvider);
    this.XXActivityMembersInjector = XXActivity_MembersInjector.create(XXPresenterProvider);
  }
    從僞代碼中能夠看出 ,定義的xxComponent會生成一個對應的DaggerXXComponent類,而且該類實現了XXComponent接口裏的方法。
  @Override
  public void inject(XXActivity activity) {
   XXActivityMembersInjector.injectMembers(activity);//將Activity注入到該類中
  }
  public static final class Builder {
    private XXModule XXModule;
    private Builder() {}
    public XXComponent build() {
      if (xxModule == null) {
        throw new IllegalStateException(XXModule.class.getCanonicalName() + " must be set");
      }
      return new DaggerXXComponent(this);
    }
    public Builder XXModule(XXModule XXModule) {
      this.XXModule = Preconditions.checkNotNull(XXModule);
      return this;
    }
  }
}
    從僞代碼中發現,Builder內部類就是用來建立module以及自身實例的,因此放在了DaggerXXComponent裏進行初始化依賴,而真正讓依賴關聯起來的就是xxActivityMembersInjector對象。
    
public final class XXActivity_MembersInjector implements MembersInjector<XXActivity> {
  private final Provider<XXPresenter> XXPresenterProvider;
  public XXActivity_MembersInjector(Provider<XXPresenter> XXPresenterProvider) {
    assert XXPresenterProvider != null;
    this.XXPresenterProvider = XXPresenterProvider;
  }
  public static MembersInjector<XXActivity> create(
      Provider<XXPresenter> XXPresenterProvider) {
    return new XXActivity_MembersInjector(XXPresenterProvider);
  }
  @Override
  public void injectMembers(XXActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.XXPresenter = XXPresenterProvider.get();
  }
  public static void injectXXPresenter(
      XXActivity instance, Provider<XXPresenter> XXPresenterProvider) {
    instance.XXPresenter = XXPresenterProvider.get();
  }
}
    從這裏發現,將xxPresenterProvider中建立好的xxPresenter實例賦值給instance的成員xxPresenter。這樣用@Inject標註的xxPresenter就獲得了實例化了,進而在代碼中進行實際使用。
 
小結:
  •   Module 並非必須品,可是Component 是必不可少的
  •    編譯後生成的Component實現類的名稱必然是:Dagger+自定義Component接口名稱
  •   在使用dagger2 時候,定義類或是方法名字的時候要遵照google的固定標準方便代碼維護
  •   定義的Component 和Module結尾同樣要以此結尾命名
  •   Module中@Provides 標註的方法要遵循規則以provide開頭命名
  •   Component中 返回值爲void且有參數的方法,參數是最重要的表明的是要注入的目標類,方法名通常使用inject
  •   Component 中返回值不爲void 且無參數,返回值是最重要的表明的是暴露給子Component 使用的依賴 或是獲取的子Component的類型
    
 
本章部份內容摘自:
感謝分享 respect
 
結語:
    儘量的達到高內聚低耦合的目標,正是呆哥兔追求的意義。
 
8、dagger2的擴展延伸-dagger.android
用於android的注入方式:
 
    @Component( modules = {AndroidInjectionModule.class,AppModule.class})
    public interface AppComponent {
        void inject(App app);
    }
 
@Subcomponent (modules = {MainActivityModule.class})
    public interface MainActivityComponent extends AndroidInjector<MainActivity>{
        void inject(MainActivity activity);
        
       @Subcomponent.Builder
        public abstrace class Builder extends AndroidInjector.Builder<MainActivity>{}
}
 
注意:
  •     在父Module中添加 @Module(subcomponents ={子Component})方式進行關聯
  •     在這樣的狀況下,子Component中必須存在被@Subcomponent.Builder標註的抽象類或是接口,不然會報異常
 
 @Module
    public class MainActivityModule{
            @Provides
            ActivityBean provideActivityBean(){
                return new ActivityBean():
            }
    }   
@Module (subcomponents = {MainActivityComponent.class});
    public abstract class AppModule{
        @Provides
        static AppBean provideAppBean(){
            return new AppBean():
        }
   @Binds
    @IntoMap
    @ActivityKey( MainActivity.class)
    abstract AndroidInjector.Factory
                        <? extends Activity>bindFactory(MainActivityComponent).inject(this);
 
在Activity中的實現:
    public class App extends Application implements HasActivityInjector{
        @Inject
            DispatchingAndroidInjector<Activity> activityInjector;
        @Override
            public void onCreate(){
            DaggerAppComponent.create().inject(htis):
        }
       @Override
            public AndroidInjector<Activity> activityInjector(){
            return activityInjector;
        }
    }
    public class MainActivity extends AppCompatActivity {
            @Inject 
            AppBean appBean;
            @Inject
            ActivityBean activityBean;
        @Override
        protected void onCreate(Bundle saveInstanceState){
            AndroidInjection.inject(this);
            super.onCreate(saveInstanceState);
            ….
        }
}
 
dagger.android 小結
     一、在AppComponent中將dagger2庫裏的AndroidInjectionModule注入到Applicaation中,並將Application實現響應的接口,並返回響應的方法;
    二、子Component繼承自AndroidInjector,內部BUilder使用抽象類並繼承AndroidInjector.Builder;
  三、父 Module 使用 @Module ( subcomponents = {} ) 的方式關聯子 Component,並在父 Module 中編寫返回值爲 AndroidInjector.Factory、參數爲子 Component.Builder 的抽象方法(若是有其餘被 @Provides 標註的方法,應將方法改成 static,不然報錯);
四、最後在 Acitivity 的 onCreate() 中第一行代碼的位置使用 AndroidInjection 注入,若是是 Fragment 則是在 onAttach() 方法中,其餘的請自行查閱。
五、dagger.android 庫也提供了其餘實現方式,諸如DaggerApplication、DaggerActivity、DaggerFragment、DaggerService、DaggerBroadcastReceiver 等實現類,有興趣的小夥伴本身研究一下吧
相關文章
相關標籤/搜索