美文网首页
走马观花-Dagger2 - 其他注解

走马观花-Dagger2 - 其他注解

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

    @Singleton

    @Singleton 注解言简意赅,就是单例的意思。也就是说,注入的依赖是个单例对象。

    BicycleModules#getBicycle() 添加 @Singleton 注解, BicycleModules 初始代码见这里

    @Module
    public class BicycleModules {
        @Provides
        @Singleton
        public Bicycle getBicycle(){
            return new Bicycle();
        }
    }
    

    编译报错:

    Error:(14, 8) 错误: [Dagger/IncompatiblyScopedBindings] com.oliver.test.bicycle.Mobai (unscoped) may not reference scoped bindings:
    @Provides @Singleton com.oliver.test.bicycle.Bicycle com.oliver.test.bicycle.BicycleModules.getBicycle()
    
    不兼容的 Scope 绑定, 说是 Mobai 没有引用 scope 绑定
    

    也就是说,假设 @Component 引用的 @Module 有提供单例对象, @Component 也必须四单例的,即也需要被 @Singleton 注解标注。

    比较 @Component 没有添加 @Singleton 注解的生成代码,不同之处在与:

     private void initialize(final Builder builder) {
        this.getBicycleProvider =
            DoubleCheck.provider(BicycleModules_GetBicycleFactory.create(builder.bicycleModules));
      }
    
    public static <P extends Provider<T>, T> Provider<T> provider(P delegate) {
        checkNotNull(delegate);
        if (delegate instanceof DoubleCheck) {
            return delegate;
        }
        return new DoubleCheck<T>(delegate);
    }
    
    private DoubleCheck(Provider<T> provider) {
        assert provider != null;
        this.provider = provider;
    }
    

    可以看出,DoubleCheck 是对 BicycleModules_GetBicycleFactory 再一层封装,并将 BicycleModules_GetBicycleFactory 赋值给 DoubleCheck 的成员变量 provider。那怎么就保证了单例呢?看看注入依赖的地方:

    @Override
     public void inject(MainActivity mainActivity) {
        injectMainActivity(mainActivity);
    }
    private MainActivity injectMainActivity(MainActivity instance) {
        MainActivity_MembersInjector.injectMBicycle(instance, getBicycleProvider.get());
        return instance;
    }
    

    也就是说,getBicycleProvider.get() 获取到的对象是单例的,再回过头看 DoubleCheck#get()

    public T get() {
        Object result = instance;
        if (result == UNINITIALIZED) {
            synchronized (this) {
                result = instance;
                if (result == UNINITIALIZED) {
                    result = provider.get();
                    instance = reentrantCheck(instance, result);
                    /* Null out the reference to the provider. We are never going to need it again, so we
               * can make it eligible for GC. */
                    provider = null;
                }
            }
        }
        return (T) result;
    }
    

    可以看出,这是一个双重锁单例机制,通过双重锁保证了 result 的唯一性,再次获取得到的是同一个对象。但是getBicycleProvider@Component 生成类的成员变量,也就是说,当我们再次 new 一个 DaggerMobai 对象时,获取到的依赖就不再是单例了。

    @Singleton 只是局部的单例,单例效果只在同一个 @Component 内有效,在不同的 @Component 对象是无效的。例如,我们再两个 Activity 中调用以下代码:

    DaggerMobai.builder()
                    .bicycleModules(new BicycleModules())
                    .build()
                    .inject(this);
    Log.d("MainActivity", mBicycle.toString());
    

    打印结果:

    MainActivity: com.oliver.test.bicycle.Bicycle@1069ab85
    MainActivity: com.oliver.test.bicycle.Bicycle@33859363
    

    因为调用 build() 方法会再次 new DaggerMobai() ,故而得到的结果非单例。

    那怎样确定一个全局单例呢?其实也简单,那就是想办法将 @Component 的作用域与 Application 绑定,这样保证了 @Component 的全局唯一性,得到的依赖自然也就全局唯一。

    首先,定义 @Module 来提供依赖,这里是 Bicycle 对象:

    @Module
    public class AppModule {
    
        @Singleton
        @Provides
        public Bicycle providerBicycle(){
            return new Bicycle();
        }
    }
    

    接着,定义 @Component

    @Singleton
    @Component(modules = {AppModule.class})
    public abstract class AppComponent {
    
        // 提供 Bicycle 对象
        // 该方法是必须的,且是 public 的
        public abstract Bicycle providerBicycle();
    }
    

    编译,生成 DaggerAppComponentAppModule_ProviderBicycleFactory:

    public final class DaggerAppComponent extends AppComponent {
      private Provider<Bicycle> providerBicycleProvider;
    
      private DaggerAppComponent(Builder builder) {
        initialize(builder);
      }
    
      public static Builder builder() {
        return new Builder();
      }
    
      public static AppComponent create() {
        return new Builder().build();
      }
    
      @SuppressWarnings("unchecked")
      private void initialize(final Builder builder) {
        this.providerBicycleProvider =
            DoubleCheck.provider(AppModule_ProviderBicycleFactory.create(builder.appModule));
      }
    
      @Override
      public Bicycle providerBicycle() {
        return providerBicycleProvider.get();
      }
    
      public static final class Builder {
        private AppModule appModule;
    
        private Builder() {}
    
        public AppComponent build() {
          if (appModule == null) {
            this.appModule = new AppModule();
          }
          return new DaggerAppComponent(this);
        }
    
        public Builder appModule(AppModule appModule) {
          this.appModule = Preconditions.checkNotNull(appModule);
          return this;
        }
      }
    }
    
    public final class AppModule_ProviderBicycleFactory implements Factory<Bicycle> {
      private final AppModule module;
    
      public AppModule_ProviderBicycleFactory(AppModule module) {
        this.module = module;
      }
    
      @Override
      public Bicycle get() {
        return provideInstance(module);
      }
    
      public static Bicycle provideInstance(AppModule module) {
        return proxyProviderBicycle(module);
      }
    
      public static AppModule_ProviderBicycleFactory create(AppModule module) {
        return new AppModule_ProviderBicycleFactory(module);
      }
    
      public static Bicycle proxyProviderBicycle(AppModule instance) {
        return Preconditions.checkNotNull(
            instance.providerBicycle(), "Cannot return null from a non-@Nullable @Provides method");
      }
    }
    

    和上面一致,其实就是使用双重锁机制保证单例。但接下来,需要将该 DaggerAppComponent 实例缓存在 Application 中,保证其全局唯一:

    public class MyApp extends Application {
    
        private static AppComponent mAppComponent;
    
        @Override
        public void onCreate() {
            super.onCreate();
            // 唯一的实例
            mAppComponent = DaggerAppComponent.create();
        }
    
        public static AppComponent getAppComponent() {
            return mAppComponent;
        }
    }
    

    接下来需要使用 AppComponent ,这里就需要用到 @Component 的另一个字段 -- dependencies:

    @Component(dependencies = {AppComponent.class})
    public interface Mobai {
    
        void inject(MainActivity mainActivity);
    
        void inject(AActivity aActivity);
    
    }
    

    再次编译,报错:

    Error:(18, 1) 错误: com.oliver.test.bicycle.Mobai (unscoped) cannot depend on scoped components:
    @Singleton com.oliver.test.app.AppComponent
    

    就是说 Mobai 没有被 @Scope 标注,不能够依赖 AppComponent。这里要说一下, @Scope 表示注入对象的作用范围, @Singleton 之所以有单例的效果,就是因为被 @Scope 注解标注 ,拥有其特性。

    添加 @Singleton ,再次编译:

    @Singleton
    @Component(modules = {BicycleModules.class} ,dependencies = {AppComponent.class})
    public interface Mobai {
    
        void inject(MainActivity mainActivity);
    
        void inject(AActivity aActivity);
    
    }
    

    再次报错:

    Error:(19, 1) 错误: This @Singleton component cannot depend on scoped components:
    @Singleton com.oliver.test.app.AppComponent
    

    即被@Singleton 标注的 @Component 不能依赖于另一个被 @Singleton 标注的 @Component 。也就是说,需要自定义一个新的 @Scope,仿照 @Singleton 创建注解 @ActivityScope:

    @Scope
    @Documented
    @Retention(RUNTIME)
    public @interface ActivityScope {
    }
    

    并使用在 Mobai 上:

    @ActivityScope
    @Component(modules = {BicycleModules.class} ,dependencies = {AppComponent.class})
    public interface Mobai {
    
        void inject(MainActivity mainActivity);
    
        void inject(AActivity aActivity);
    
    }
    

    再次编译,通过。再次运行程序,在两个不同的 Activity 添加如下代码:

    DaggerMobai.builder()
                    .appComponent(MyApp.getAppComponent())
                    .build()
                    .inject(this);
    Log.d("MainActivity", mBicycle.toString());
    

    得到结果:

    MainActivity: com.oliver.test.bicycle.Bicycle@1069ab85
    MainActivity: com.oliver.test.bicycle.Bicycle@1069ab85
    

    至此,全局单例就得到了。

    根据调用来看,全局单例的形成肯定和这句代码息息相关:

    appComponent(MyApp.getAppComponent())
    

    因为在 DaggerAppComponent 中得到的 Bicycle 单例的

     private void initialize(final Builder builder) {
        this.providerBicycleProvider =
            DoubleCheck.provider(AppModule_ProviderBicycleFactory.create(builder.appModule));
      }
    
      @Override
      public Bicycle providerBicycle() {
        return providerBicycleProvider.get();
      }
    

    DaggerAppComponentApplication 中初始化,也保证了其唯一性。故而:

    DaggerMobai.builder()
                    .appComponent(MyApp.getAppComponent())
                    .build()
                    .inject(this);
    

    应该是由 appComponent(MyApp.getAppComponent()) 提供依赖,保证唯一。具体看 DaggerMobai 源码:

    public final class DaggerMobai implements Mobai {
      private AppComponent appComponent;
    
      private DaggerMobai(Builder builder) {
        initialize(builder);
      }
    
      public static Builder builder() {
        return new Builder();
      }
    
      @SuppressWarnings("unchecked")
      private void initialize(final Builder builder) {
        this.appComponent = builder.appComponent;
      }
    
      @Override
      public void inject(MainActivity mainActivity) {
        injectMainActivity(mainActivity);
      }
    
      @Override
      public void inject(AActivity aActivity) {
        injectAActivity(aActivity);
      }
    
      private MainActivity injectMainActivity(MainActivity instance) {
        MainActivity_MembersInjector.injectMBicycle(
            instance,
            Preconditions.checkNotNull(
                appComponent.providerBicycle(),
                "Cannot return null from a non-@Nullable component method"));
        return instance;
      }
    
      private AActivity injectAActivity(AActivity instance) {
        AActivity_MembersInjector.injectMBicycle(
            instance,
            Preconditions.checkNotNull(
                appComponent.providerBicycle(),
                "Cannot return null from a non-@Nullable component method"));
        return instance;
      }
    
      public static final class Builder {
        private AppComponent appComponent;
    
        private Builder() {}
    
        // 可以看到,appComponent()方法是必须调用的
        public Mobai build() {
          if (appComponent == null) {
            throw new IllegalStateException(AppComponent.class.getCanonicalName() + " must be set");
          }
          return new DaggerMobai(this);
        }
    
        @Deprecated
        public Builder bicycleModules(BicycleModules bicycleModules) {
          Preconditions.checkNotNull(bicycleModules);
          return this;
        }
    
        public Builder appComponent(AppComponent appComponent) {
          this.appComponent = Preconditions.checkNotNull(appComponent);
          return this;
        }
      }
    }
    

    通过注入代码可知,确实是由 AppComponent 来提供依赖,这也正是需要在 AppComponent 中存在提供依赖的方法的原因。

    private AActivity injectAActivity(AActivity instance) {
        AActivity_MembersInjector.injectMBicycle(
            instance,
            Preconditions.checkNotNull(
                appComponent.providerBicycle(),
                "Cannot return null from a non-@Nullable component method"));
        return instance;
      }
    

    小结:

    • @Singleton 注解只是局部单例
    • 如果 @Module 中使用了 @Singleton ,那么对应的 @Component 中也需要被 @Singleton 标注
    • @Component 依赖的另一个 @Component 使用了 @Scope,本 @Component 不能再使用相同的 @Scope 或者是不使用 @Scope ,而是需要重新定义一个。
    • 定义全局单例依赖,需要在 AppComponent 中定义提供依赖的方法

    @Named

    假设一个类,我们需要两个不同的对象,那么,在 @Module 中可以这样:

    @Module
    public class CarModules {
    
        @Provides
        public Car providerCarA() {
            return new Car("本田");
        }
    
        @Provides
        public Car providerCarB() {
            return new Car("兰博基尼");
        }
    }
    

    Car

    public class Car {
        @Inject
        public Car(String info) {
            System.out.println("I'm a Car -- " + info);
        }
    }
    

    可以看出,存在了两个方法来提供不同的 Car 实例。编译,报错:

    Error:(17, 10) 错误: [Dagger/DuplicateBindings] com.oliver.test.car.Car is bound multiple times:
    @Provides com.oliver.test.car.Car com.oliver.test.car.CarModules.providerCarA()
    @Provides com.oliver.test.car.Car com.oliver.test.car.CarModules.providerCarB()
    
    com.oliver.test.car.Car is injected at
    com.oliver.test.MainActivity.mCarA
    com.oliver.test.MainActivity is injected at
    com.oliver.test.car.Ofo.inject(com.oliver.test.MainActivity)
    

    这是因为提供了两个 Car 对象,然后在 MainActivity 中也有两个 Car 实例等待注入,Dagger 并不知道两者之间的对应关系是怎样的?

    public class MainActivity extends AppCompatActivity {
    
        @Inject
        @Named("A")
        Car mCarA;
    
        @Inject
        @Named("B")
        Car mCarB;
    }
    

    Dagger 不知道哪个生成的 Car 该注入到mCarA, 哪个该注入到mCarB,故而报错。解决这个问题,就要让Dagger 知道他们的对应关系。这里有两个方法可以办到,分别是 @Named@Qualifier。其实, @Named 就是被 @Qualifier 所标注的,故而也就一种方法。

    先看看 @Named 的使用:

    @Module
    public class CarModules {
    
        @Provides
        @Named("A")
        public Car providerCarA() {
            return new Car("本田");
        }
    
        @Provides
        @Named("B")
        public Car providerCarB() {
            return new Car("兰博基尼");
        }
    }
    

    MainActivity 中:

    public class MainActivity extends AppCompatActivity {
    
        @Inject
        @Named("A")
        Car mCarA;
    
        @Inject
        @Named("B")
        Car mCarB;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            DaggerOfo.builder().build().inject(this);
        }
    }
    

    编译运行,打印结果如下:

    System.out: I'm a Car -- 本田
    System.out: I'm a Car -- 兰博基尼
    

    @Qualifier

    标识限定符注释,@Named 其实就是一个@Qualifier

    现在通过定义新的 @Qualifier 来改造上面的例子:

    首先定义两个 @Qualifier ,分别为 CarACarB:

    @Qualifier
    @Documented
    @Retention(RUNTIME)
    public @interface CarA {
    }
    
    @Qualifier
    @Documented
    @Retention(RUNTIME)
    public @interface CarB {
    }
    

    然后在依赖提供处和依赖需求处使用:

    @Module
    public class CarModules {
    
        @Provides
        @CarA
        public Car providerCarA() {
            return new Car("本田");
        }
    
        @Provides
        @CarB
        public Car providerCarB() {
            return new Car("兰博基尼");
        }
    }
    
    public class MainActivity extends AppCompatActivity {
    
        @Inject
        @CarA
        Car mCarA;
    
        @Inject
        @CarB
        Car mCarB;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerOfo.builder().build().inject(this);
    
        }
    }
    

    编译运行,打印结果如下:

    System.out: I'm a Car -- 本田
    System.out: I'm a Car -- 兰博基尼
    

    @Lazy

    @Lazy 起到一个懒加载的作用,也就是当你需要该依赖的时候,才通过 get() 方法获取,第一次获取会进行 new 操作,接下来就会取上次的缓存直接返回。通过源码:

    public class MainActivity extends AppCompatActivity {
        @Inject
        @CarA
        Lazy<Car> mCarLazyA;
    
        @Inject
        @CarB
        Lazy<Car> mCarLazyB;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            DaggerOfo.builder().build().inject(this);
    
            Log.d("MainActivity", "mCarLazyA.get():" + mCarLazyA.get());
            Log.d("MainActivity", "mCarLazyB.get():" + mCarLazyB.get());
        }
    }
    

    DaggerOfo 注入源码:

    @Override
      public void inject(MainActivity activity) {
        injectMainActivity(activity);
      }
    
      private MainActivity injectMainActivity(MainActivity instance) {
        MainActivity_MembersInjector.injectMCarLazyA(instance, DoubleCheck.lazy(providerCarAProvider));
        MainActivity_MembersInjector.injectMCarLazyB(instance, DoubleCheck.lazy(providerCarBProvider));
        return instance;
      }
    

    由上可知,对依赖使用 Lazy<T> ,其实真正的赋值类型是 DoubleCheck,也就是调用 get() 方法才能获取到真正的 Car 对象,并且保证了对象的复用。

    @Subcomponent

    • 使用

    1、定义一个被 @Module 标注的接口

    @Module
    public class BicycleModules {
    }
     由于这里测试的是 @Subcomponent 注解,注入由 @Component 提供的依赖,故而该接口不写任何方法。当然,假设需要自身提供任何依赖,也可以加上 @provider 方法
    

    2、定义一个被 @Subcomponent 标注的接口

    @Subcomponent(modules = {BicycleModules.class})
    public interface Ofo {
        void inject(MainActivity activity);
    }
    

    3、将该接口使用在被 @Component 标注的类中

    @Component(modules = {AppModule.class})
    public abstract class AppComponent {
    
        public abstract Bicycle providerBicycle();
    
        public abstract Ofo addOfoSub(BicycleModules bicycleModules);
    }
    

    4、在 MainActivity 中使用

        @Inject
        Bicycle mBicycle;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            DaggerAppComponent.builder().build().addOfoSub(new BicycleModules()).inject(this);
            Log.d("MainActivity", "mBicycle:" + mBicycle);
        }
    

    @Subcomponent 标注的类不会生成 DaggerXxxComponent 类,但是会在使用他的 @Component 类中生成对应的 名字+Impl 实现类,例如,Ofo 生成类为 OfoImpl.

    public final class DaggerAppComponent extends AppComponent {
        private Provider<Bicycle> providerBicycleProvider;
    
        private DaggerAppComponent(Builder builder) {
            initialize(builder);
        }
    
        public static Builder builder() {
            return new Builder();
        }
    
        public static AppComponent create() {
            return new Builder().build();
        }
    
        @SuppressWarnings("unchecked")
        private void initialize(final Builder builder) {
            this.providerBicycleProvider =
                    DoubleCheck.provider(AppModule_ProviderBicycleFactory.create(builder.appModule));
        }
    
        @Override
        public Bicycle providerBicycle() {
            return providerBicycleProvider.get();
        }
    
        @Override
        public Ofo addOfoSub(BicycleModules bicycleModules) {
            return new OfoImpl(bicycleModules);
        }
    
        public static final class Builder {
            private AppModule appModule;
    
            private Builder() {
            }
    
            public AppComponent build() {
                if (appModule == null) {
                    this.appModule = new AppModule();
                }
                return new DaggerAppComponent(this);
            }
    
            public Builder appModule(AppModule appModule) {
                this.appModule = Preconditions.checkNotNull(appModule);
                return this;
            }
        }
    
        private final class OfoImpl implements Ofo {
            private OfoImpl(BicycleModules bicycleModules) {
            }
    
            @Override
            public void inject(MainActivity activity) {
                injectMainActivity(activity);
            }
    
            private MainActivity injectMainActivity(MainActivity instance) {
                MainActivity_MembersInjector.injectMBicycle(
                        instance, DaggerAppComponent.this.providerBicycleProvider.get());
                return instance;
            }
        }
    }
    

    当我们在 MainActivity 中调用这句代码时:

    DaggerAppComponent.builder().build().addOfoSub(new BicycleModules()).inject(this);
    

    可以在 DaggerAppComponent#OfoImpl 中看到,会将 @Component 提供的 Bicycle 对象赋值给 MainActivity 的依赖变量 mBicycle.

    具体 @Component#dependencies@SubComponent 区别可见这里

    相关文章

      网友评论

          本文标题:走马观花-Dagger2 - 其他注解

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