zoukankan      html  css  js  c++  java
  • Dagger2 (三) 总结篇

    一.Dagger2注入原理

    Dagger2以自动生成代码的形式,帮助我们构建依赖图,在使用依赖的时候方便清晰,这里说明一点,在我们使用Dagger2的时候,绝大多数错误都是编译器就会暴漏出来,这也就决定了这套框架的稳定性会更高。

    关于生成的源码,我们一起看一下。我们就以之前提到的例子来看:

    @Generated("dagger.internal.codegen.ComponentProcessor")
    public final class DaggerApplicationComponent implements ApplicationComponent {
      private Provider<Application> applicationProvider;
      private Provider<Context> contextProvider;
    
      private DaggerApplicationComponent(Builder builder) {  
        assert builder != null;
        initialize(builder);
      }
    
      public static Builder builder() {  
        return new Builder();
      }
    
      private void initialize(final Builder builder) {  
        this.applicationProvider = ApplicationModule_ApplicationFactory.create(builder.applicationModule);
        this.contextProvider = ApplicationModule_ContextFactory.create(builder.applicationModule);
      }
    
      @Override
      public Application application() {  
        return applicationProvider.get();
      }
    
      @Override
      public Context context() {  
        return contextProvider.get();
      }
    
      public static final class Builder {
        private ApplicationModule applicationModule;
        private GsonModule gsonModule;
    
        private Builder() {  
        }
    
        public ApplicationComponent build() {  
          if (applicationModule == null) {
            throw new IllegalStateException("applicationModule must be set");
          }
          if (gsonModule == null) {
            this.gsonModule = new GsonModule();
          }
          return new DaggerApplicationComponent(this);
        }
    
        public Builder applicationModule(ApplicationModule applicationModule) {  
          if (applicationModule == null) {
            throw new NullPointerException("applicationModule");
          }
          this.applicationModule = applicationModule;
          return this;
        }
    
        public Builder gsonModule(GsonModule gsonModule) {  
          if (gsonModule == null) {
            throw new NullPointerException("gsonModule");
          }
          this.gsonModule = gsonModule;
          return this;
        }
      }
    }
    

    可以看到DaggerApplicationComponent中,有一个建造者模式来构建一个ApplicationComponent对象,这也帮我们初始化了两个Module中的依赖,但是注意,这里并没有直接初始化所有模块内的依赖,而只是初始化了组件对象而已。

    可以看到initialize方法中有两个工厂方法。

    @Generated("dagger.internal.codegen.ComponentProcessor")
    public final class ApplicationModule_ContextFactory implements Factory<Context> {
      private final ApplicationModule module;
    
      public ApplicationModule_ContextFactory(ApplicationModule module) {  
        assert module != null;
        this.module = module;
      }
    
      @Override
      public Context get() {  
        Context provided = module.context();
        if (provided == null) {
          throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
        }
        return provided;
      }
    
      public static Factory<Context> create(ApplicationModule module) {  
        return new ApplicationModule_ContextFactory(module);
      }
    }
    

    可以看出这个工厂中一直保留着ApplicationModule,当我们每次获取依赖,则会重新调用Module的context()方法,即如果里面是new的形式提供依赖 ,则会重新创建对象。

    而反观我们用PerActivity标注的ToasterProvider:

    @Generated("dagger.internal.codegen.ComponentProcessor")
    public final class DaggerActivityComponent implements ActivityComponent {
      private Provider<Context> contextProvider;
      private MembersInjector<BaseActivity> baseActivityMembersInjector;
      private Provider<Toaster> provideToasterProvider;
      private Provider<Toaster> provideTheToasterProvider;
    
      private DaggerActivityComponent(Builder builder) {  
        assert builder != null;
        initialize(builder);
      }
    
      public static Builder builder() {  
        return new Builder();
      }
    
      private void initialize(final Builder builder) {  
        this.contextProvider = new Factory<Context>() {
          private final ApplicationComponent applicationComponent = builder.applicationComponent;
          @Override public Context get() {
            Context provided = applicationComponent.context();
            if (provided == null) {
              throw new NullPointerException("Cannot return null from a non-@Nullable component method");
            }
            return provided;
          }
        };
        this.baseActivityMembersInjector = BaseActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), contextProvider);
        this.provideToasterProvider = ScopedProvider.create(ActivityUtilModule_ProvideToasterFactory.create(builder.activityUtilModule));
        this.provideTheToasterProvider = ActivityUtilModule_ProvideTheToasterFactory.create(builder.activityUtilModule);
      }
    
      @Override
      public void inject(BaseActivity activity) {  
        baseActivityMembersInjector.injectMembers(activity);
      }
    
      @Override
      public Toaster theToaster() {  
        return provideToasterProvider.get();
      }
    
      @Override
      public Toaster toaster() {  
        return provideTheToasterProvider.get();
      }
    
      public static final class Builder {
        private ActivityUtilModule activityUtilModule;
        private ApplicationComponent applicationComponent;
    
        private Builder() {  
        }
    
        public ActivityComponent build() {  
          if (activityUtilModule == null) {
            throw new IllegalStateException("activityUtilModule must be set");
          }
          if (applicationComponent == null) {
            throw new IllegalStateException("applicationComponent must be set");
          }
          return new DaggerActivityComponent(this);
        }
    
        public Builder activityUtilModule(ActivityUtilModule activityUtilModule) {  
          if (activityUtilModule == null) {
            throw new NullPointerException("activityUtilModule");
          }
          this.activityUtilModule = activityUtilModule;
          return this;
        }
    
        public Builder applicationComponent(ApplicationComponent applicationComponent) {  
          if (applicationComponent == null) {
            throw new NullPointerException("applicationComponent");
          }
          this.applicationComponent = applicationComponent;
          return this;
        }
      }
    }
    

    provideToasterProvider则和其他初始化方式不同,可以看到后面ProviderToaster的工厂很普通:

    @Generated("dagger.internal.codegen.ComponentProcessor")
    public final class ActivityUtilModule_ProvideToasterFactory implements Factory<Toaster> {
      private final ActivityUtilModule module;
    
      public ActivityUtilModule_ProvideToasterFactory(ActivityUtilModule module) {  
        assert module != null;
        this.module = module;
      }
    
      @Override
      public Toaster get() {  
        Toaster provided = module.provideToaster();
        if (provided == null) {
          throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
        }
        return provided;
      }
    
      public static Factory<Toaster> create(ActivityUtilModule module) {  
        return new ActivityUtilModule_ProvideToasterFactory(module);
      }
    }
    
    

    那么ScopedProvider.create包住的工厂有什么特别的呢?

    public final class ScopedProvider<T> implements Provider<T> {
      private static final Object UNINITIALIZED = new Object();
    
      private final Factory<T> factory;
      private volatile Object instance = UNINITIALIZED;
    
      private ScopedProvider(Factory<T> factory) {
        assert factory != null;
        this.factory = factory;
      }
    
      @SuppressWarnings("unchecked") // cast only happens when result comes from the factory
      @Override
      public T get() {
        // double-check idiom from EJ2: Item 71
        Object result = instance;
        if (result == UNINITIALIZED) {
          synchronized (this) {
            result = instance;
            if (result == UNINITIALIZED) {
              instance = result = factory.get();
            }
          }
        }
        return (T) result;
      }
    
      /** Returns a new scoped provider for the given factory. */
      public static <T> Provider<T> create(Factory<T> factory) {
        if (factory == null) {
          throw new NullPointerException();
        }
        return new ScopedProvider<T>(factory);
      }
    }
    

    我们看下源码,这里的create是创建了一个ScopeProvider的对象,并将工厂传入,当这个ScopeProvider去get的时候,内部有个单例来维持这个对象,这就是为什么我们自定义注解是个单例的秘密。

    接下来看看神器的注解是怎么起作用的。

    public final class BaseActivity_MembersInjector implements MembersInjector<BaseActivity> {
        private final MembersInjector<FragmentActivity> supertypeInjector;
        private final Provider<Context> contextProvider;
    
        public BaseActivity_MembersInjector(MembersInjector<FragmentActivity> supertypeInjector, Provider<Context> contextProvider) {
            assert supertypeInjector != null;
    
            this.supertypeInjector = supertypeInjector;
    
            assert contextProvider != null;
    
            this.contextProvider = contextProvider;
        }
    
        public void injectMembers(BaseActivity instance) {
            if(instance == null) {
                throw new NullPointerException("Cannot inject members into a null reference");
            } else {
                this.supertypeInjector.injectMembers(instance);
                instance.context = (Context)this.contextProvider.get();
            }
        }
    
        public static MembersInjector<BaseActivity> create(MembersInjector<FragmentActivity> supertypeInjector, Provider<Context> contextProvider) {
            return new BaseActivity_MembersInjector(supertypeInjector, contextProvider);
        }
    }
    

    在我们注入这个对象后,injectMembers方法中,写明了BaseActivity中的context对象是从ContextProvider的get方法中得到,根据代码也可以看到,这部分依赖是从ApplicationComponent中的provideContext方法取得。

    再看看Lazy Load:

    public final class DoubleCheckLazy<T> implements Lazy<T> {
      private static final Object UNINITIALIZED = new Object();
    
      private final Provider<T> provider;
      private volatile Object instance = UNINITIALIZED;
    
      private DoubleCheckLazy(Provider<T> provider) {
        assert provider != null;
        this.provider = provider;
      }
    
      @SuppressWarnings("unchecked") // cast only happens when result comes from the factory
      @Override
      public T get() {
        // to suppress it.
        Object result = instance;
        if (result == UNINITIALIZED) {
          synchronized (this) {
            result = instance;
            if (result == UNINITIALIZED) {
              instance = result = provider.get();
            }
          }
        }
        return (T) result;
      }
    
      public static <T> Lazy<T> create(Provider<T> provider) {
        if (provider == null) {
          throw new NullPointerException();
        }
        return new DoubleCheckLazy<T>(provider);
      }
    }
    

    toasterLazy加载的时候是使用DoubleCheckLazy.create(this.toasterLazyProvider)来进行初始化。而内部是个单例,只有在get时才会初始化。

    至此,Dagger2的主要源码就差不多理解了。

    二.使用分析

    Dagger2很优雅,优雅到你可以特别轻松的调试它,以为他和你手写的代码几乎一模一样,又优雅到几乎所有的错误都从编译器暴露出。

    与RoboGuice的反射不同,生成代码必然会导致方法数的增加。但是,我们可以看到生成的代码数量并不多,而且在实际应用过程中也可以看出,确实影响不大,这个可以大家在以后的使用中慢慢体会。

    性能上Dagger2会优于RoboGuice,尤其是天生支持懒加载,但是在易用性上,RoboGuice更容易上手和理解,并且针对Android做了很多通用依赖,为项目开发提高便利。

    综上,如果是一个小而美的应用,使用RoboGuice可以快速帮你完成开发工作,而Dagger2在长期来看,性能和效率更佳。

    至此,Dagger2入坑系列结束。

  • 相关阅读:
    BFS visit tree
    Kth Largest Element in an Array 解答
    Merge k Sorted Lists 解答
    Median of Two Sorted Arrays 解答
    Maximal Square 解答
    Best Time to Buy and Sell Stock III 解答
    Best Time to Buy and Sell Stock II 解答
    Best Time to Buy and Sell Stock 解答
    Triangle 解答
    Unique Binary Search Trees II 解答
  • 原文地址:https://www.cnblogs.com/pedro-neer/p/5309841.html
Copyright © 2011-2022 走看看