美文网首页Android 入门进阶
Dagger 2学习与探索(二)

Dagger 2学习与探索(二)

作者: akak18183 | 来源:发表于2017-08-20 10:00 被阅读100次

    上一期我们用最简单的例子来实现了Dagger的依赖注入,虽然对过程大致有了了解,但是还有很多功能和部件还没有被使用。
    这一期我们更进一步,在ClassA里面添加一个参数,来看看Dagger是如何运作的。

    代码主体

    首先在ClassA添加一个新的成员变量:

    public class ClassA {
    
      private int a;
    
      @Inject
      public ClassA(int a) {
        this.a = a;
      }
    
      public int getA() {
        return a;
      }
    }
    

    那么之前的ClassA_Factory需要知道ClassA的参数,当然这里有@Inject可以让Dagger读取参数表。另一个问题就是,怎么传入参数?
    此时就不得不提到Module了。如果说Component是注入器的话,Module则是负责产生所需参数的部件。来看看代码:

    @Module
    public class ModuleA {
      private int a;
      public ModuleA(int a) {
        this.a = a;
      }
    
      @Provides
      int provideInt() {
        return a;
      }
    }
    

    可以看到,与Component是接口不同,'Module'其实是用'@Module'标注的对象,有构造器。值得一提的是里面包含的用'@Provides'标注的方法,这就是提供参数时产生作用的函数,其名字无关紧要,只要返回类型能对上号就行。那么这里就有一个问题,有多个同类型的怎么办呢?这就涉及到另外一些标注了,此处暂且不提。
    那么Component是如何与'Module'相连接的?答案是通过标注参数:

    @Component(modules = ModuleA.class)
    public interface ClassAComponent {
      void inject(MainActivity activity);
    }
    

    同样可以预见的是实现注入的代码肯定也有变化:
    DaggerClassAComponent.builder().moduleA(new ModuleA(2333)).build().inject(this);
    即需要传入'Module'从而提供注入所需参数。可能你说,这不还是new了吗?这里new的是'Module',可没有new一个ClassAClassA的产生确实已经委托出去了。
    MainActivity的代码:

    public class MainActivity extends AppCompatActivity {
      @Inject ClassA classA;
      private static final String TAG = "MainActivity";
    
      @Override
      protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerClassAComponent.builder()
            .moduleA(new ModuleA(2333))
            .build().inject(this);
        Log.d(TAG, classA.getA() + "");
      }
    }
    

    生成代码

    'Module'的加入究竟导致了哪些变化?来看看生成代码吧。

    ClassA_Factory

    public final class ClassA_Factory implements Factory<ClassA> {
      private final Provider<Integer> aProvider;
    
      public ClassA_Factory(Provider<Integer> aProvider) {
        assert aProvider != null;
        this.aProvider = aProvider;
      }
    
      @Override
      public ClassA get() {
        return new ClassA(aProvider.get());
      }
    
      public static Factory<ClassA> create(Provider<Integer> aProvider) {
        return new ClassA_Factory(aProvider);
      }
    }
    

    与上一次的ClassA_Factory有稍许不同,这次工厂构建方法需要一个Provider<Integer> aProvider来提供创建'ClassA'时所需的参数。

    ModuleA_ProvideIntFactory

    这是一个新的文件:

    public final class ModuleA_ProvideIntFactory implements Factory<Integer> {
      private final ModuleA module;
    
      public ModuleA_ProvideIntFactory(ModuleA module) {
        assert module != null;
        this.module = module;
      }
    
      @Override
      public Integer get() {
        return Preconditions.checkNotNull(
            module.provideInt(), "Cannot return null from a non-@Nullable @Provides method");
      }
    
      public static Factory<Integer> create(ModuleA module) {
        return new ModuleA_ProvideIntFactory(module);
      }
    
      /** Proxies {@link ModuleA#provideInt()}. */
      public static int proxyProvideInt(ModuleA instance) {
        return instance.provideInt();
      }
    }
    

    还是一个工厂,接受ModuleA,然后使用其provideInt()方法来产生int参数。你可能会问,那为什么不直接用ModuleA呢?嗯,好问题。我现在还不知道,继续看。

    MainActivity_MembersInjector

    没有变化,还是贴出来。

    public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
      private final Provider<ClassA> classAProvider;
    
      public MainActivity_MembersInjector(Provider<ClassA> classAProvider) {
        assert classAProvider != null;
        this.classAProvider = classAProvider;
      }
    
      public static MembersInjector<MainActivity> create(Provider<ClassA> classAProvider) {
        return new MainActivity_MembersInjector(classAProvider);
      }
    
      @Override
      public void injectMembers(MainActivity instance) {
        if (instance == null) {
          throw new NullPointerException("Cannot inject members into a null reference");
        }
        instance.classA = classAProvider.get();
      }
    
      public static void injectClassA(MainActivity instance, Provider<ClassA> classAProvider) {
        instance.classA = classAProvider.get();
      }
    }
    

    DaggerClassAComponent

    public final class DaggerClassAComponent implements ClassAComponent {
      private Provider<Integer> provideIntProvider;
    
      private Provider<ClassA> classAProvider;
    
      private MembersInjector<MainActivity> mainActivityMembersInjector;
    
      private DaggerClassAComponent(Builder builder) {
        assert builder != null;
        initialize(builder);
      }
    
      public static Builder builder() {
        return new Builder();
      }
    
      @SuppressWarnings("unchecked")
      private void initialize(final Builder builder) {
    
        this.provideIntProvider = ModuleA_ProvideIntFactory.create(builder.moduleA);
    
        this.classAProvider = ClassA_Factory.create(provideIntProvider);
    
        this.mainActivityMembersInjector = MainActivity_MembersInjector.create(classAProvider);
      }
    
      @Override
      public void inject(MainActivity activity) {
        mainActivityMembersInjector.injectMembers(activity);
      }
    
      public static final class Builder {
        private ModuleA moduleA;
    
        private Builder() {}
    
        public ClassAComponent build() {
          if (moduleA == null) {
            throw new IllegalStateException(ModuleA.class.getCanonicalName() + " must be set");
          }
          return new DaggerClassAComponent(this);
        }
    
        public Builder moduleA(ModuleA moduleA) {
          this.moduleA = Preconditions.checkNotNull(moduleA);
          return this;
        }
      }
    }
    

    可以看到,现在Builder就要求传入一个ModuleA,然后在initialize方法里面把上面介绍的几个组合起来,最终实现依赖注入。

    下期我们将再添加一个int参数,来看看Dagger是如何应对多参数以及同类型参数的。

    相关文章

      网友评论

      本文标题:Dagger 2学习与探索(二)

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