dagger2 学习(三) - scope 使用

关于Scope

Dagger 2 自带的 Scope 只有一个 @Singleton ,其他的可以通过自定义来实现

本文代码

1. 前言

(1) Scope 的作用,就是提供在当前 Component 实例 范围内的单例。

假设 DaggerUserComponent 能够提供 User 实例

UserComponent 被自定义的 @UserScope 标注,那就意味着

一旦一个 DaggerUserComponent 实例创建完成,

那么其调用 injectTo 方法,进行注入时,所有注入的 User 对象都是同一个实例

知道 DaggerUserComponent 被重新创建,才会提供一个不一样的User实例

(2) @Scope 的使用方法

第一种

  1. @Scope 注解整个 Bean 对象,@inject 注解对应 Bean 对象的构造方法
  2. @Scope 还需要在 Bean 对象注入,出现的 Component 中标注

第二种

  1. @Scope 配合 在Module 中使用,配合 @Provides 一起标注
  2. @Scope 需要在 Module 出现的 Component 中标注

两种方法,其实就是两种提供实例的不同实现,对比前面 一二两篇文章即可看出

第一种是最简单注入时,加上@Scope

第二种是配合@Module 注入式,加上@Scope


2. 进行实践操作

(1) 整体结构构建

实践的内容主要是针对 @Scope 第二种使用方法

因此这�中间@UserScope 只需要添加到 UserModuleUserComponent

具体代码

整个类的结构

代码结构

创建三个 Activity 分别用于显示 User 实例

下面贴出部分代码

自定义 UserScope.java

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface UserScope {
}

User.java

public class User {
    ...//纯 Bean 对象,无任何特殊
}

UserComponent.java

@UserScope// 绑定 UserScope
@Component(modules = {UserModule.class})
public interface UserComponent {
    void injectTo(ClassARoomActivity classARoomActivity);
    void injectTo(ClassBRoomActivity classBRoomActivity);
}

UserModule.java

@Module
public class UserModule {
    ...
    @UserScope// 绑定 UserScope
    @Provides
    User provideUser(){
        return new User();
    }
}

App.java

    ...
    static UserComponent sUserComponent;
    ...
    public static UserComponent getUserComponent(){// 获取 DaggerUserComponent 对象
        if (sUserComponent == null){
            sUserComponent = DaggerUserComponent.builder().userModule(new UserModule())
                    .build();
        }
        return sUserComponent;
    }

    public static void releaseUserComponent(){ // 清空 DaggerUserComponent 对象
        sUserComponent = null;
    }
    ...

(2) 具体生成代码和调用分析

a. 代码生成部分分析

DaggerUserComponent.java 部分代码变化

未加上 @UserScope 时,provideUserProvider 的生成

this.provideUserProvider = UserModule_ProvideUserFactory.create(builder.userModule);

加上 @UserScope 后,provideUserProvider 的生成

this.provideUserProvider =
    DoubleCheck.provider(UserModule_ProvideUserFactory.create(builder.userModule));

注意,虽然此处的 provideUserProvider 依然是 Provider

但是,其实它的实例已经是 DoubleCheck 类型的。

跟进这个DoubleCheck.provider() 方法

  public static  Provider provider(Provider delegate) {
    checkNotNull(delegate);
    if (delegate instanceof DoubleCheck) {
    // 如果是 DoubleCheck 的实例,直接返回
      return delegate;
    }
    // 否则创建一个,此处的 delegate 就是 UserModule_ProvideUserFactory.create(builder.userModule)
    return new DoubleCheck(delegate);
  }

跟进构造方法

private DoubleCheck(Provider provider) {
  assert provider != null;
  this.provider = provider;
  // 啥都没有,就是赋值了一个 provider 引用
}

所以综上,可以判断出,和之前的没有@UserScope 注解对比,具体的实例提供者改变了,不是生成UserModule_ProvideUserFactory 对象了,变成了DoubleCheck 对象,其内部持有一个 UserModule_ProvideUserFactory 的引用。

b.整体调用链

DaggerUserComponent.injectTo -> ClassARoomActivity_MembersInjector.injectMembers() -> mUserProvider.get() -> DoubleCheck.get()

下面进行具体分析

  • DaggerUserComponent.injectTo -> ClassARoomActivity_MembersInjector.injectMembers() 部分

    因此其调用的实例也有了对应的改变,对应的xxxInjector.javainjectMemebers 方法在调用时,会调用不同的实例

    该部分代码和之前并无区别,主要是运行时,实例的区别

    @Override
    public void injectTo(ClassARoomActivity classARoomActivity) {
      classARoomActivityMembersInjector.injectMembers(classARoomActivity);
    }
    
    @Override
    public void injectMembers(ClassARoomActivity instance) {
      if (instance == null) {
        throw new NullPointerException("Cannot inject members into a null reference");
      }
      instance.mUser = mUserProvider.get();// 注意该部分会调用不同的实例对应的方法
    }
    
  • mUserProvider.get() -> DoubleCheck.get()

    未加上@UserScop 时,实例是 UserModule_ProvideUserFactory

    调用的是UserModule_ProvideUserFactory.java 中的方法,如下

        @Override
        public User get() {
          return Preconditions.checkNotNull(
            module.provideUser(), "Cannot return null from a non-@Nullable @Provides method");
        }
    

    加上@UserScop 时,实例是DoubleCheck

    调用的是 DoubleCheck 中的方法,如下,该部分也是实现 Scope 功能重要的一部分

       public T get() {
                   Object result = instance;
                   if (result == UNINITIALIZED) {// 如果该对象从来没有初始化,那就初始化一次
                     synchronized (this) {
                       result = instance;// 获取最新实例,防止线程之间同时修改
                       if (result == UNINITIALIZED) {
                         result = provider.get();// 此处依旧调用了 UserModule_ProvideUserFactory.get() 方法
                         Object currentInstance = instance;
                         if (currentInstance != UNINITIALIZED && currentInstance != result) {
                           throw new IllegalStateException("Scoped provider was invoked recursively returning "
    + "different results: " + currentInstance + " & " + result);
               }
          instance = result;
          // 赋值最新的值
          provider = null;
          // 初始化一次以后,该对象对应的 Provider 在当前 Scope 中其实已经没有意义了,
          // 所以直接置为空,方便 GC 回收
        }
      }
    }
    return (T) result;// 返回结果
    }
    
    
    >注意,Provider 的置空
    >
    >此处的置空不会影响数据的获取,该 `provider` 的引用就是下面方法中的 `UserModule_ProvideUserFactory.create(builder.userModule)` 对
    >
    >```java
    >this.provideUserProvider =  DoubleCheck.provider(UserModule_ProvideUserFactory.create(builder.userModule));
    >```
    
    
    
    
    
    

3. 总结

总结:

@UserScope 作用于 Component 生命周期内

限制了被标注的实例提供者,只会实例化该对象一次,之后会抛弃对应的 Provider ,然后永远获取之前创建的User

@UserScope @Provides provideUser() ==> UserModule_ProviderUserFactory

此处抛弃的就是 UserModule_ProviderUserFactory 的实例

只有当实例化的 Component 对象被重新构建,被标注的实例提供者才会重新创建

dagger2 学习(三) - scope 使用_第1张图片
Dagger2 学习(三)

一家之言,仅供参考

本文代码

你可能感兴趣的:(dagger2 学习(三) - scope 使用)