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 等实现类,有兴趣的小伙伴本身研究一下吧
相关文章
相关标签/搜索