Dagger2轻松上手

Dagger2是由google接手的*** dependency injection***(依赖注入)框架,今天我们来拨开dagger2的迷雾。这篇文章主要介绍Dagger2的简单用法,内容包括

  • @Inject
  • @Component
  • @Module
  • @Provides
  • @Singleton
首先来看下@Inject ,先看一段代码
public class User {
  @Inject 
  public User () { };

@Inject
public void setName ( ){}
.......
}

public class UserActivity extends AppCompatActivity {
      ......
      @Inject User user;
      ......
}
  

该注解作用域有三个:

  • 属性
  @Inject User user

@Inject 表明这里需要一个User类实例,由Dagger2 完成赋值,注意:该属性作用域必须为 public

  • 方法
@Inject public void setName ( ){}

** @Inject 在这里的作用是:当构造函数完成后,立即调用该函数,一般用来调用参数为 this 的方法**

  • 构造函数
 @Inject 
  public User () { };

@inject 标记这是一个被依赖的类,Dagger2 负责生成这个类的实例。需要注意的是,如果构造函数有参数,那么参数的构造方法也必须有@Inject 标记,直到某个参数的构造函数不需要参数

@Component
@Component
public interface IUserComponent {
      
    User getUser () ;
    void inject (UserActivity activity) ;
}

Component 是连接依赖方与被依赖方的桥梁,而且类型必须为接口或者抽象类,插件会自动生成该类的实例,名字一般为Dagger+该接口/抽象类。该接口一般有两种方法:

  • 提供被依赖类
  object getObjecet() //对应上面 getUser ( ) 提供被依赖类
  • 注入依赖类
/**
*比如上面 UserActivity 依赖 User,
*UserActivity 就象一个容器,由Dagger 注入 User 实例
*/
  void inject ( 目标容器)

编译一下,插件会自动生成Dagger*Component实体类,
我们只需在UserActivity 中使用一行代码便可完成注入,具体注入下文有说到。

 @Override
    public void onCreate (Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerIUserComponent.builder().build().inject(this);
    }
@Module

Module 的作用也是提供依赖类,那么 InjectModule 有什么区别呢?
Inject主要用于我们自己创建的类,或者说我们可以改变其构造函数的类,比如,如果你的构造函数是这样的:

...
@Inject
public User (String name) {......}
...

上面我们就提过,对于有参数的构造函数,其参数的构造函数也必须有@Inject标记,显然,我们无法对String的构造函数进行更改。
这时候就需要@ModuleModule可以给不能修改源码的类提供依 赖,当然,能用Inject标注的通过Module也可以提供依赖我们更改下部分代码:

...
public class User {
  @Inject 
  public User (String name) { };
}
...
@Component (modules = UserModule.class)
public interface IUserComponent {

        void inject(UserActivity activity);
        User getUser();
}
.....
@Module
public class UserModule {
    private String name;
    
    public UserModule(String name){
        this.name = name;
    }
    
    @Provides
    User provideUser() {return new User(name);}
}

我们新建一个Module类,然后在@Component后面指定范围 (modules = UserModule.class),这提醒Dagger 到 UserModule 获取User实例

@Provides

用Provide来标注一个方法,该方法可以在需要提供依赖类时被调用,provide主要用于标注Module里的方法。
编译一下,看下生成代码:

public final class DaggerIUserComponent implements IUserComponent {
  private Provider provideUserProvider;

  private MembersInjector userActivityMembersInjector;

  private DaggerIUserComponent(Builder builder) {
    assert builder != null;
    initialize(builder);
  }

  public static Builder builder() {
    return new Builder();
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {

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

    this.userActivityMembersInjector = UserActivity_MembersInjector.create(provideUserProvider);
  }

  @Override
  public void inject(UserActivity activity) {
    userActivityMembersInjector.injectMembers(activity);
  }

  @Override
  public User getUser() {
    return provideUserProvider.get();
  }

  public static final class Builder {
    private UserModule userModule;

    private Builder() {}

    public IUserComponent build() {
      if (userModule == null) {
        throw new IllegalStateException(UserModule.class.getCanonicalName() + " must be set");
      }
      return new DaggerIUserComponent(this);
    }

    public Builder userModule(UserModule userModule) {
      this.userModule = Preconditions.checkNotNull(userModule);
      return this;
    }
  }
}

可以看到有两个变量provideUserProvideruserActivityMembersInjector
看下inject 函数 ,userActivityMembersInjector调用injectMembers(UserActivity acativity)函数

 @Override
  public void injectMembers(UserActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.user = userProvider.get(); //关键代码,完成注入
  }

我们很清楚的看到Dagger通过直接对变量的引用实现代码注入,这也是为什么变量的作用域必须是 public,这时又有一个新变量userProvider,我们看下它的来历。

public final class UserActivity_MembersInjector {
......
public UserActivity_MembersInjector(Provider userProvider) {
      assert userProvider != null;
      this.userProvider = userProvider;
  }
......
public static MembersInjector create(Provider userProvider) {
    return new UserActivity_MembersInjector(userProvider);
  }
}

它是做参数传入构造器的,我们来看下什么时候传入的参数

public final class DaggerIUserComponent implements IUserComponent {
private void initialize(final Builder builder) {
......
    this.provideUserProvider = UserModule_ProvideUserFactory.create(builder.userModule);

    this.userActivityMembersInjector = UserActivity_MembersInjector.create(provideUserProvider);
  }
......
}

又涉及到一个新类UserModule_ProvideUserFactory

public final class UserModule_ProvideUserFactory implements Factory {
  private final UserModule module;

  public UserModule_ProvideUserFactory(UserModule module) {
    assert module != null;
    this.module = module;
  }

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

它接受一个UserModule作为参数。在get()中调用Module的方法,实现依赖类的注入。
所以我们在UserActivity中可以很轻松的实现注入

 DaggerIUserComponent.builder()
                            .userModule(new UserModule("name"))
                            .build()
                            .inject(this);
@Singleton

我们来看下@Singleton使用:
我们改下代码

@Module
public class UserModule {
......
    @Provides
    @Singleton   //添加注解
    User provideUser() {return new User(name);}
.....
}
/**
*同时修改Component
*/
@Component (modules = UserModule.class)
@Singleton
public interface IUserComponent {

        void inject(UserActivity activity);
        User getUser();
}
......
public class UserActivity extends AppCompatActivity {
    @Inject
    public User user;
    @Inject User user1;  //增加一个变量
    @Override
    public void onCreate (Bundle savedInstanceState){
    ......
        Log.e("TAG",user.hashCode() +"---"+user1.hashCode());  //打印哈希值
    }
}

Paste_Image.png

我们很清楚的看到,两个引用的哈希值一样,证明两个引用指向同一对象,说明使用 @Singleton标记,和我们使用单例模式是一样的。

以上就是这篇文章的全部内容,谢谢观赏。

参考资料:

浅析Dagger2的使用

你可能感兴趣的:(Dagger2轻松上手)