走马观花-Dagger2 - 其他注解

@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 区别可见这里

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容

  • 前言 继上篇文章,这篇我们来学习Dagger2的高级用法。如果没看上篇文章的话最好先看下上篇文章再来学习本章,因为...
    g小志阅读 597评论 0 2
  • 什么的依赖注入 在软件工程中,依赖注入是实现控制反转的方式之一。百度百科中对于控制反转的解释如下:控制反转(Inv...
    小甜李子阅读 1,678评论 5 3
  • 1.Dagger2简介 1.1 Dagger2的描述 Github地址:Dagger2 Dagger2官网上介绍是...
    橙子只涩不酸阅读 799评论 0 1
  • Dagger2入门详解 @(Android) Dagger2入门详解 参考文章 环境配置 入门实例 其他注解和情况...
    JFang阅读 596评论 1 0
  • 赶在黄昏之前 阳光调皮地 溜过树叶间的空隙 凝射出一道道有力的光线 散落成一颗颗晃烁的碎钻 那光斑啊 一闪一闪地收...
    留下痕迹_must阅读 251评论 0 2