美文网首页
走马观花-Dagger2 - @Inject 和 @Compon

走马观花-Dagger2 - @Inject 和 @Compon

作者: OkCoco | 来源:发表于2019-02-15 10:08 被阅读0次

    @Inject

    • @Inject 使用在一个类的属性上,表示该类需要一个依赖
    • @Inject 使用在一个类的构造方法上,表示由该构造方法提供依赖

    假设有个路人Passerby,需要一辆车Car,则可以表示为 Passerby 依赖于 Car。代码表示:

    Passerby :

    public class Passerby {
        public Car mCar;
        public Passerby(Car car) {
            mCar = car;
            System.out.println("I'm a Passerby!");
        }
    }
    

    Car :

    public class Car {
        @Inject
        public Car() {
            System.out.println("I'm a Car!");
        }
    }
    

    当且仅当在 Car 的构造器上使用 @Inject 时,编译,在 \build\generated\source\apt\debug\com\oliver\test 目录下自动生成了 Car_Factory.java 文件:

    public final class Car_Factory implements Factory<Car> {
      private static final Car_Factory INSTANCE = new Car_Factory();
    
      @Override
      public Car get() {
        return provideInstance();
      }
    
      public static Car provideInstance() {
        return new Car();
      }
    
      public static Car_Factory create() {
        return INSTANCE;
      }
    
      public static Car newCar() {
        return new Car();
      }
    }
    

    Car_Factory 实现了 Factory<T> 接口, Factory<T> 继承至 Provider<T> 接口:

    public interface Factory<T> extends Provider<T> {
    }
    
    public interface Provider<T> {
        /**
         *  返回注入的实例
         */
        T get();
    }
    

    观察 Car_Factory.java ,可以知道:

    • 构造器使用了 @Inject 注解,就会生成 类名_FactoryFactory<T> 实现类。
    • get() 确实返回我们注入的实例
    • 自动生成两个返回 new Car() 的方法,分别是 newCar()provideInstance()

    Passerby 的依赖标注 @Inject 注解,再次编译:

     @Inject
     public Car mCar;
    

    \build\generated\source\apt\debug\com\oliver\test 目录下多了一个 Passerby_MembersInjector 的类:

    public final class Passerby_MembersInjector implements MembersInjector<Passerby> {
      private final Provider<Car> mCarProvider;
    
      public Passerby_MembersInjector(Provider<Car> mCarProvider) {
        this.mCarProvider = mCarProvider;
      }
    
      public static MembersInjector<Passerby> create(Provider<Car> mCarProvider) {
        return new Passerby_MembersInjector(mCarProvider);
      }
    
      @Override
      public void injectMembers(Passerby instance) {
        injectMCar(instance, mCarProvider.get());
      }
    
      public static void injectMCar(Passerby instance, Car mCar) {
        instance.mCar = mCar;
      }
    }
    

    该类实现了 MembersInjector<T> 接口:

    public interface MembersInjector<T> {
      void injectMembers(T instance);
    }
    

    注意 Passerby_MembersInjector 的方法 injectMembers(T instance),其参数是 Passerby 类型,也就是说,该方法的使命就是给其参数持有的成员变量赋值,然后外界想办法获得这个参数就行了,参数依赖的对象已经在此处完成了注入的过程。

     @Override
      public void injectMembers(Passerby instance) {
        injectMCar(instance, mCarProvider.get());
      }
    
      public static void injectMCar(Passerby instance, Car mCar) {
        instance.mCar = mCar;
      }
    

    另外, Passerby_MembersInjector 多出了一个成员 Provider<Car>,即一个类的成员变量标注有 @Inject 注解,那么这个成员就会在生成类中生成相应的 Provider<T> 成员。根据上面对 Car_Factory 的分析,大胆猜测,其实这里的 Provider<Car> 就是生成的 Car_Factory 。所需依赖也正好在此处注入,即:

    instance.mCar =  mCarProvider.get();
    mCar = new Car();
    
    
    ///////////////////////////// Car_Factory /////////////////////////////
    @Override
    public Car get() {
        return provideInstance();
    }
    
    public static Car provideInstance() {
        return new Car();
    }
    

    上面说到,我们猜测 Provider<Car> 就是生成的 Car_Factory 。那 Provider<Car> 是怎样赋值的呢?

    public Passerby_MembersInjector(Provider<Car> mCarProvider) {
        this.mCarProvider = mCarProvider;
      }
    
      public static MembersInjector<Passerby> create(
          Provider<Car> mCarProvider) {
        return new Passerby_MembersInjector(mCarProvider);
      }
    

    可以看到,主要是通过 Passerby_MembersInjector.create()new Passerby_MembersInjector()赋值,其中 create() 又是直接调用构造方法的。那这两个方法是调用了哪一个?谁调用的?这就要说到另外一个注解了: @Component

    Dagger 的主要功能时依赖注入,从而达到解耦的目的。所以不会在Xxx_MembersInjector 中直接赋值,这样的话和 mCar = new Car() 没什么区别?所以我猜测,引入了 @Component 是为了达到依赖方和被依赖方不直接耦合的目的。但是,这样就造成了依赖方和被依赖方都与 @Component 耦合了。所以其实我也不太清楚 @Component 的具体作用

    2019-02-12
    @Component 限定了提供依赖的 Module 类,如果有过多个 Module 都提供该依赖,@Componentmodules 字段就指定了到底是哪个具体 Module 来完成这个依赖的提供。

    @Component

    @Inject 使用在成员上表示需要依赖对象,使用在构造器上表示提供自身对象。两者之间需要 @Component 注解作为依赖关系形成的桥梁。

    @Component 使用在接口或抽象类上,编译后在 \build\generated\source\apt\debug\com\oliver\test 目录下生成一个名称为 Dagger + 被注解的类名称 的类。例如:

    @Component
    public interface Ofo {}
    

    生成类名称: DaggerOfo

    @Component 必须包含至少一个abstract component method,以下简称 CMCM 可以随意命名,但是必须有满足 Provider 或者 MembesInjector 约束的签名。

    Provider Method :

    Provider Method,以下简称 PM ,没有参数但是有返回值。返回一个 {@link Inject injected}{@link Provides provided} 类型,方法还可以被 @Qualifier 注解标注。也就是说,返回值必须是 被注入类型被提供类型

    • 被注入类型 表示其构造器被 @Inject 标注
    • 被提供类型 表示 @Component 包含的 @Module 中被 @Providers 注解标注的方法的返回值类型

    注解 @Module@Providers 是什么?下面会说到。

    MembersInjector Method :

    MembersInjector Method ,以下简称 MMMM 有一个参数,并将依赖项注入每个 {@link Inject} 注解的字段和传递实例的方法,MM 返回 void, 为方便链式调用,也可返回 参数类型,。也就是说,参数类中有成员变量被 @Inject 标注,且该成员变量类的构造器也被 @Inject 标注。这样的话,当 @Compment 实现类【DaggerOfo】重写该方法【void inject(MainActivity activity)】时,就会通过成员变量相应生成的【Passerby_Factory】构造【Passerby】实例,赋值给参数【MainActivity】的成员变量【mPasserby】。具体如下:

    public class Passerby {
        @Inject
        public Car mCar;
    
        public Passerby(){}
    
        @Inject
        public Passerby(Car car) {
            mCar = car;
            System.out.println("I'm a Passerby!");
        }
        public void go(){
            mCar.go();
        }
    }
    

    MainActivity 中使用:

    public class MainActivity extends AppCompatActivity {
    
        @Inject
        Passerby mPasserby;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            // 注意,此处注入的参数this不能为null,
            DaggerOfo.builder().build().inject(this);
            mPasserby.go();
        }
    }
    

    开始使用 @Component 注解:

    @Component
    public interface Ofo {
        
    //    Passerby getPasserby();
        
        // 使用 MembersInjector Method
        void inject(MainActivity activity);
    }
    

    在标注了 @Component 注解的类中使用 MM,生成类如下:

    public final class DaggerOfo implements Ofo {
      private DaggerOfo(Builder builder) {}
    
      public static Builder builder() {
        return new Builder();
      }
    
      public static Ofo create() {
        return new Builder().build();
      }
    
      private Passerby getPasserby() {
        return injectPasserby(Passerby_Factory.newPasserby(new Car()));
      }
    
      @Override
      public void inject(MainActivity activity) {
        injectMainActivity(activity);
      }
    
      private Passerby injectPasserby(Passerby instance) {
        Passerby_MembersInjector.injectMCar(instance, new Car());
        return instance;
      }
    
      private MainActivity injectMainActivity(MainActivity instance) {
        MainActivity_MembersInjector.injectMPasserby(instance, getPasserby());
        return instance;
      }
    
      public static final class Builder {
        private Builder() {}
    
        public Ofo build() {
          return new DaggerOfo(this);
        }
      }
    }
    

    可以看到,当我们调用 inject() 时,会调用到 Passerby_MembersInjector#injectMCar():

    public static void injectMCar(Passerby instance, Car mCar) {
        // 直接赋值,假设传进来的 instance == null,报空指针就在所难免了
        instance.mCar = mCar;
    }
    

    调用 injectMainActivity(MainActivity) 之后,在层层调用,就达到了给成员变量 mPasserbyPasserby 的成员变量 mCar 的注入。

    现在在 @Component 注解的类中使用 MP:

    @Component
    public interface Ofo {
    
        Passerby getPasserby();
    
    //    void inject(Passerby passerby);
    }
    

    生成类 DaggerOfo 如下:

    public final class DaggerOfo implements Ofo {
        private DaggerOfo(Builder builder) {}
    
        public static Builder builder() {
            return new Builder();
        }
    
        public static Ofo create() {
            return new Builder().build();
        }
    
        @Override
        public Passerby getPasserby() {
            return injectPasserby(Passerby_Factory.newPasserby(new Car()));
        }
    
        private Passerby injectPasserby(Passerby instance) {
            Passerby_MembersInjector.injectMCar(instance, new Car());
            return instance;
        }
    
        public static final class Builder {
            private Builder() {}
    
            public Ofo build() {
                return new DaggerOfo(this);
            }
        }
    }
    

    可以看到,调用 getPasserby() 时会自动生成一个 Passerby 实例,然后给其注入依赖。外界可通过返回值获取到该实例。

    总结

    • @Inject 使用在一个类的属性上,表示该类需要一个依赖;使用在一个类的构造方法上,表示由该构造方法提供依赖
    • @Component 注解作为依赖关系形成的桥梁,至少包含一个 CM。编译之后会生成 DaggerXxx
    • CM类型是 MM ,在类【假设为A】中使用 DaggerXxx ,则 A 中必须有 @Inject 注解标注的成员变量,用于赋值。因为经过上面生成的 DaggerOfo 来说,在 injectXxx() 中都是这样模板代码:instance.mXxx = Xxx_Factory.newXxx(),即赋值操作。
    • CM类型是 PM , 在类【假设为A】中使用 DaggerXxx 来获取需要注入的对象,然后在使用;例如:
    Passerby mPasserby = DaggerOfo.builder().build().getPasserby();
    mPasserby.go();
    

    相关文章

      网友评论

          本文标题:走马观花-Dagger2 - @Inject 和 @Compon

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