Dagger2利器系列三:原理、用途

355 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

一:dagger2的好处or用途

1.1 一切都是为了解耦

一切都是为了解耦。

一个类的new代码是非常可能充斥在app的多个类中的,假如该类的构造函数发生变化,那这些涉及到的类都得进行修改。设计模式中提倡把容易变化的部分封装起来。

我们用了dagger2后,假如是通过用Inject注解标注的构造函数创建类实例,则即使构造函数变的天花乱坠,我们基本上都不需要修改任何代码。假如是通过工厂模式Module创建类实例,Module其实就是把new类实例的代码封装起来,这样即使类的构造函数发生变化,只需要修改Module即可。

我认为如果是小app一般没必要用到Daggger2(为了学习还是好的),解耦也是要付出相应的空间和时间代价的,工作量和复杂度都可能会提高(多人协作大项目会提高你的效率),编译时也容易出错,但在解耦数据和业务逻辑方面,Dagger2无愧利器之名。

1.2 增加开发效率

这里的开发效率着重于:省去重复而又无意义new实例对象代码。当然这也会增加我们一些依赖包括module、component等代码的铺垫,但做完这些铺垫,dagger2就可以把new一个实例的工作做了,从而让开发者把精力集中在业务上。

一个很棒的例子就是Dagger2中单例的写法,开发者不需要担心自己写的单例方法是否线程安全,懒汉or饿汉模式,这些Dagger2都会帮你搞定。

1.3 更好的管理类实例

每个app中的ApplicationComponent管理整个app的全局类实例,所有的全局类实例都统一交给ApplicationComponent管理,并且它们的生命周期与app的生命周期一样。 每个页面对应自己的Component,页面Component管理着自己页面所依赖的所有类实例。因为Component,Module,整个app的类实例结构变的很清晰。

二 原理分析

在大体介绍完 Dagger2 后,我们分析一下实现原理。

《Dagger2利器系列一:入门到使用》中最简单的 案例A:入门demo为例,Dagger2 在编译时根据注解生成一些辅助类,我们具体分析下生成的辅助类。辅助类可以通过 DaggerXXXComponent 来快速定位。上面两个例子对应生成辅助类如下:

我们分析下具体的注入过程,首先 Car 中会调用DaggerCarComponent.builder().build().inject(this);,我们来看下 DaggerCarComponent 的源码:

public final class DaggerCarComponent implements CarComponent {
  private DaggerCarComponent() {

  }

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

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

  @Override
  public void inject(Car car) {
    injectCar(car);}

  private Car injectCar(Car instance) {
    Car_MembersInjector.injectEngine(instance, new Engine());
    return instance;
  }

  public static final class Builder {
    private Builder() {
    }

    public CarComponent build() {
      return new DaggerCarComponent();
    }

  }
}

可以看到,DaggerCarComponent 是CarComponent的实现类,最终调用到了inject方法里的injectCar方法,然后调用了injectCar方法里的 Car_MembersInjector.injectEngine(instance, new Engine());

我们来看下Car_MembersInjector的源码:

public final class Car_MembersInjector implements MembersInjector<Car> {
  private final Provider<Engine> engineProvider;

  public Car_MembersInjector(Provider<Engine> engineProvider) {
    this.engineProvider = engineProvider;
  }

  public static MembersInjector<Car> create(Provider<Engine> engineProvider) {
    return new Car_MembersInjector(engineProvider);}

  @Override
  public void injectMembers(Car instance) {
    injectEngine(instance, engineProvider.get());
  }

  @InjectedFieldSignature("com.ysalliance.getfan.daggertest.Car.engine")
  public static void injectEngine(Car instance, Engine engine) {
    instance.engine = engine;
  }
}

可以看到,这是Car对应的@Inject。

Engine_Factory对应的源码:

public final class Engine_Factory implements Factory<Engine> {
  @Override
  public Engine get() {
    return newInstance();
  }

  public static Engine_Factory create() {
    return InstanceHolder.INSTANCE;
  }

  public static Engine newInstance() {
    return new Engine();
  }

  private static final class InstanceHolder {
    private static final Engine_Factory INSTANCE = new Engine_Factory();
  }
}

可以看到,Engine_Factory,是Engine构造方法的@Inject。

上面是最简单的Dagger2的注入原理的分析,如果想看带@Module 和 @Provides的稍微复杂一点的Dagger2的注入原理,推荐看这一篇博文:《Dagger2 使用及原理分析》,相信在这篇的基础上,学习带@Module 和 @Provides的注入原理,更加水到渠成。

参考文章:

dagger2到底有哪些好处?

关于Android Dagger2 应用的疑惑?