AAC学习笔记之Dagger(一)

本文为《Android Architecture Components学习笔记》的一部分
文档代码为Kotlin,但是系统生成的代码仍然为Java
本人水平有限,如有不当之处请不吝赐教

Dagger初接触

Dagger并不是AAC的一部分,但是在项目中却是个狠角色。Dagger的应用对项目组件解耦以及单元测试还是会带来许多益处。所以,我觉得有必要好好研究一下。
刚开始接触Dagger2时,感觉就像简称D(dan)T(teng)。随着谷歌接手维护以来这种情况得到了一些改善,同时谷歌也赋予了更多的功能。

需要说明的是这里的Dagger-Android与Dagger2并不是一回事。


通过一个非常简单的栗子,来说明Dagger最基础的用法。
我有一个Person

class Person  {
    var name: String
    var age: Int

    constructor() {
        this.name = "超越"
        this.age = 28
    }

    override fun toString(): String {
        return "Person(name='$name', age=$age)"
    }

}

普通的用法MainActivity

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
		……
        var person=Person()
        ……
    }
}

我们来看看用Dagger是怎么实现的:

  • 第一步、将被注入类的构造器加@Inject注解
class Person  {
    var name: String
    var age: Int

    @Inject//构造函数加上这个注解
    constructor() {
        this.name = "超越"
        this.age = 28
    }

    override fun toString(): String {
        return "Person(name='$name', age=$age)"
    }

}
  • 第二步、需要一个组件接口,建一个PersonComponent
@Component//必须用@Component注解
interface PersonComponent {
     //接口、函数名可以自己起,参数必须是注入目标类
     fun injectMain(mainActivity: MainActivity):Unit

第三步、Build一下,然后MainActivity里:

class MainActivity() : AppCompatActivity(){
    @Inject//这样写代表注入了变量
    lateinit var person:Person

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)
        //前两步完成Build一下就会有DaggerPersonComponent
        DaggerPersonComponent.create().injectMain(this)
        Log.v("111", person.toString())
    }
}

OK,这是Dagger最简单的用法。


简单原理

用了三步即可完成Dagger注入,下面就简单看看如何实现的。

被注入类

在被注入类(这里指的是Person)的构造函数前面加上@Inject注解并Build项目后,会自动生成一个***_Factory的类,看看下面的代码:

public final class Person_Factory implements Factory<Person> {
  private static final Person_Factory INSTANCE = new Person_Factory();

  @Override
  public Person get() {return provideInstance();  }

  public static Person provideInstance() { return new Person(); }
  public static Person_Factory create() { return INSTANCE; }
  public static Person newPerson() {return new Person(); }
}

这个自动生成的类用来返回一个Person对象
如果不熟悉工厂模式,可以看一下FactoryProvider

注入目标类

我们是要将Person注入到MainActivity
所以在MainActivityperson变量加上@Inject
Build后会生成MainActivity_MembersInjector类:

public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
  private final Provider<Person> personProvider;

  public MainActivity_MembersInjector(Provider<Person> personProvider) {
    this.personProvider = personProvider;
  }

  public static MembersInjector<MainActivity> create(Provider<Person> personProvider) {
    return new MainActivity_MembersInjector(personProvider);
  }

  //后面两个方法完成了注入
  @Override
  public void injectMembers(MainActivity instance) {
    injectPerson(instance, personProvider.get());
  }

  public static void injectPerson(MainActivity instance, Person person) {
    instance.person = person;
  }
}

组件接口

注入类与目标类都生成了相应的代码,那么他们是怎样联系在一起的呢。
写一个用@Component标注的接口PersonComponent
Build后会生成DaggerMainActivityComponent类:

public final class DaggerPersonComponent implements PersonComponent {
  private DaggerPersonComponent(Builder builder) {}

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

  //在MainActivity里我们先调用了这个方法
  public static PersonComponent create() {return new Builder().build();}

  //在MainActivity里调用create()后直接调用这个方法
  @Override
  public void injectMain(MainActivity mainActivity) {injectMainActivity(mainActivity); }

  private MainActivity injectMainActivity(MainActivity instance) {
    //我用版本比较新,这个场景下,没用到被注入类的_Factory。
    //之前java下是要使用Person_Factory.create()的,而且代码冗余。
    MainActivity_MembersInjector.injectPerson(instance, new Person());
    return instance;
  }

  public static final class Builder {
    private Builder() {}
    public PersonComponent build() {return new DaggerPersonComponent(this);}
  }
}

Component起到了组装的作用。


简单用Module

如果被注入类是别人的,比如网络请求、图片处理或其他等等
是没办法在构造器上加@Inject,就需要使用Module了

改一下Person:

data class Person(var name: String, var age: Int) {

    override fun toString(): String {
        return "Person(name='$name', age=$age)"
    }
}

前面Person类延用了Java的风格,这里用Kotlin支持的data class简单多了。

  • 首先,建一个用@Module注解的Module类
@Module//必须用这个注解
class PersonModule {
    @Provides//也是必须的
    fun person(): Person {
        return Person("高歌", 28)
    }
}
  • 然后,在Component上引用
//新版的modules=后边是个array
@Component(modules = [PersonModule::class])
interface PersonComponent {
    fun injectMain(mainActivity: MainActivity):Unit
}

然后Build即可。

完成后Person_Factory就没有了,会生成PersonModule_PersonFactory

public final class PersonModule_PersonFactory implements Factory<Person> {
  private final PersonModule module;
  public PersonModule_PersonFactory(PersonModule module) {this.module = module;}

  @Override
  public Person get() { return provideInstance(module); }

  public static Person provideInstance(PersonModule module) { return proxyPerson(module);}

  public static PersonModule_PersonFactory create(PersonModule module) {
    return new PersonModule_PersonFactory(module);
  }

  public static Person proxyPerson(PersonModule instance) {
    return Preconditions.checkNotNull( instance.person(), "Cannot ……"); }
}

DaggerMainActivityComponent里,会加上PersonModule_PersonFactory

public final class DaggerPersonComponent implements PersonComponent {
  private PersonModule personModule;

  private DaggerPersonComponent(Builder builder) {initialize(builder);}

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

  public static PersonComponent create() {return new Builder().build(); }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) { this.personModule = builder.personModule; }

  @Override
  public void injectMain(MainActivity mainActivity) {injectMainActivity(mainActivity);}

  private MainActivity injectMainActivity(MainActivity instance) {
   
    //这里变了,之前就是简单的new Person()
    MainActivity_MembersInjector.injectPerson(
        instance, PersonModule_PersonFactory.proxyPerson(personModule));
    return instance;
  }

  public static final class Builder {

    private PersonModule personModule;
    private Builder() {}

    public PersonComponent build() {
      if (personModule == null) {this.personModule = new PersonModule();}
      return new DaggerPersonComponent(this);
    }

    public Builder personModule(PersonModule personModule) {
      this.personModule = Preconditions.checkNotNull(personModule);
      return this;
    }
  }
}

MainActivity_MembersInjector还是那个样。

总结一下

先到这里吧,这篇主要是简单说明一下Dagger的基本注入原理。
使用上也不难:

  • 分别在注入与被注入的类里使用@Inject注解
  • 需要注入的类初始化配置,就放在Module里
  • 做一个用@Component注解的Component
  • 最后就可以使用系统生成的Dagger****注入了

几个需要注意的事项:

  • 使用@Inject注解的成员不能是private的
  • 组件接口名最好以Component结尾
  • Component里注入接口参数不能是注入类型的父类或子类

猜你喜欢

转载自blog.csdn.net/jouter/article/details/83301653
今日推荐