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入坑系列结束。

  • 相关阅读:
    Android学习笔记【07】【四大组件之广播接收者】
    Android Adapter、Activity回传数据、发送短信
    Android学习笔记【06】【四大组件之Activity】
    Android学习笔记【05】【网络编程之二】
    Android学习笔记【04】【网络编程之一】
    Android学习笔记【03】【数据存储与数据展示】
    【转】sql server获取数据库名,表明,表结构
    C# 打开默认浏览器
    winform 重绘listbox
    字符串数组的简单应用,字符换行,c#,asp.net
  • 原文地址:https://www.cnblogs.com/pedro-neer/p/5309841.html
Copyright © 2011-2022 走看看