看源码学dagger2

看源码学dagger2


为什么要学习dagger2

在项目中,我们经常要使用到各种各样的工具和业务模块。好的项目会采用模块化编程,把业务模块做成一个个组件,通过适配器实现接口和app相连接。这样降低了耦合,在多人协作项目中避免各人项目互相依赖,提高了开发效率,更加便于维护。但是在项目中,仍然避免不了实例化接口的时候造成耦合。dagger2就是为了解决这个问题而出现的。它通过对象工厂实例化对象,然后依赖注入到目标类中,不需要再通过在目标类中用new创建对象。这样在以后如果对象有变化的时候,只要修改对象工厂相关的类就可以,不必在目标类中进行修改。下面我们来学习一下如何使用dagger2。

dagger2中的角色介绍

dagger2主要有2个角色,一个是Component,一个是Module。
Component是连接目标类和它所依赖对象的桥梁。一方面它通过依赖Module获取对象,一方面它定义了那些类可以作为目标类接收这些对象的注入。

Component的代码如下

@Component(modules = MainModule.class)
public interface MainComponent {
    PetDelegate petDelegate();
    void inject(MainActivity mainActivity);

代码中的Component叫MainComponent,注解@Component表示这是一个Component。modules =表示MainComponent依赖的moudle 是MainModule.class,moudle可以是多个。
Module的作用是提供对象。

Module的代码如下

@Module
public class MainModule {
    @Provides
    PetDelegate providePetDelegate(){
        return new DogAdapter();
    }
}

@Module表示MainModule一个Module,@Provides表示这是一个提供对象的方法。这两段代码结合起来作用就是MainComponent从moudule中获得了PetDelegate对象的实例,并把它注入到MainActivity的中PetDelegate属性中。
注:PetDelegate是一个接口,DogAdapter实现了它。
下面我们看看dagger是如何创建一个对象并把它注入到目标类中的


dagger2的基本用法

dagger创建对象有2种方法。分别是通过对象的构造函数创建和通过moudle创建。通过moudle创建的方式上面已经介绍过了,下面介绍下通过对象构造方法创建。

public class User1 implements Serializable {
    private String name;
    private String pwd;

    @Inject
    public User1() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
}

在User1类的构造方法中加上注解 @Inject表示从类的构造方法中获取。

对象创建已经准备就绪了,下面我们build一下工程,让dagger的代码生成器生成代码(对通过注解生成代码感兴趣的童鞋可以了解下AbstractProcessor方面内容),build完成后,我们把它注入到目标类中。注入代码如下

public class MainActivity extends AppCompatActivity {
    @Inject
    protected PetDelegate petDelegate1;
    @Inject
    protected User1 u;
    private ActivityMainBinding mDataBinding;
    private AlertDialog.Builder mBulider;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        DaggerMainComponent.builder().mainModule(new      MainModule()).build().inject(this);
        mDataBinding = DataBindingUtil.setContentView(this, R.layout.activity_main);
        mDataBinding.setVariable(BR.event, new EventHandler());
    }
    .....

我们看到MainActivity的两个属性上面也有 @Inject注解,不要把它们和之前构造方法上面的@Inject搞混了。属性上面的@Inject注解表示这个属性用来接收注入的实例,而构造方法上面的@Inject表示通过这个方法提供对象实例。还有一点要注意,属性不能是private,至于为什么这样,下面看了源码大家就知道了。让我们点开DaggerMainComponent(dagger2生成的类),看看它搞的是哪一出吧。
DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(this);看这段代码就知道 DaggerMainComponent采用了构建者设计模式,它里面有一个内部类负责构建它需要的属性,那我们先从 Builder 来看吧。

public static final class Builder {
    private MainModule mainModule;

    private Builder() {}

    public MainComponent build() {
      if (mainModule == null) {
        this.mainModule = new MainModule();
      }
      return new DaggerMainComponent(this);
    }

    public Builder mainModule(MainModule mainModule) {
      this.mainModule = Preconditions.checkNotNull(mainModule);
      return this;
    }
  }

从上面的代码可以看出Builder保存了MainComponent依赖的Module,并把自己传入了MainComponent的构造方法。

  private Provider<PetDelegate> providePetDelegateProvider;

  private MembersInjector<MainActivity> mainActivityMembersInjector;

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

MainComponent构造方法只有一个方法initialize(builder);进去看看

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

    this.providePetDelegateProvider =
        MainModule_ProvidePetDelegateFactory.create(builder.mainModule);

    this.mainActivityMembersInjector =
        MainActivity_MembersInjector.create(providePetDelegateProvider, User1_Factory.create());
  }

initialize的作用是给MainComponent的providePetDelegateProvider和mainActivityMembersInjector属性赋值。MainModule_ProvidePetDelegateFactory和MainActivity_MembersInjector看上去是二个对象工厂,进去看看。
MainModule_ProvidePetDelegateFactory的代码

  private Provider<PetDelegate> providePetDelegateProvider;

  private MembersInjector<MainActivity> mainActivityMembersInjector;

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

MainComponent构造方法只有一个方法initialize(builder);进去看看

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

    this.providePetDelegateProvider =
        MainModule_ProvidePetDelegateFactory.create(builder.mainModule);

    this.mainActivityMembersInjector =
        MainActivity_MembersInjector.create(providePetDelegateProvider, User1_Factory.create());
  }

这段代码中MainComponent的属性providePetDelegateProvider和mainActivityMembersInjector被赋值。
我们看看MainModule_ProvidePetDelegateFactory和 MainActivity_MembersInjector这两个工厂类里面做了什么。

MainModule_ProvidePetDelegateFactory的代码如下

 public final class MainModule_ProvidePetDelegateFactory implements Factory<PetDelegate> {
  private final MainModule module;

  public MainModule_ProvidePetDelegateFactory(MainModule module) {
    assert module != null;
    this.module = module;
  }

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

  public static Factory<PetDelegate> create(MainModule module) {
    return new MainModule_ProvidePetDelegateFactory(module);
  }

  /** Proxies {@link MainModule#providePetDelegate()}. */
  public static PetDelegate proxyProvidePetDelegate(MainModule instance) {
    return instance.providePetDelegate();
  }
}

MainModule_ProvidePetDelegateFactory实现了Factory接口。

public interface Factory<T> extends Provider<T> {
}
public interface Provider<T> {
    T get();
}

Factory接口继承了Provider接口,Provider接口有一个方法get。我们看在MainModule_ProvidePetDelegateFactoryget方法的实现,它里面调用了 module.providePetDelegate(),看到这里我们就明白了,对象是在这里实例化的。

providePetDelegateProvider获取到值后,传给MainActivity_MembersInjector的create方法,同时还有一个User1_Factory.create()。
User1_Factory的代码如下

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

  @Override
  public User1 get() {
    return new User1();
  }

  public static Factory<User1> create() {
    return INSTANCE;
  }
}

User1_Factory用饿汉式单例获取工厂对象,它的get方法创建User1对象。原来用@Inject构造方法实例化对象是这样实现的。
这样MainActivity的两个属性的对象创建工具都获取到了。MainActivity_MembersInjector做什么我们大致也可以猜到了。下面看看它的代码

public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
  private final Provider<PetDelegate> petDelegate1Provider;

  private final Provider<User1> uProvider;

  public MainActivity_MembersInjector(
      Provider<PetDelegate> petDelegate1Provider, Provider<User1> uProvider) {
    assert petDelegate1Provider != null;
    this.petDelegate1Provider = petDelegate1Provider;
    assert uProvider != null;
    this.uProvider = uProvider;
  }

  public static MembersInjector<MainActivity> create(
      Provider<PetDelegate> petDelegate1Provider, Provider<User1> uProvider) {
    return new MainActivity_MembersInjector(petDelegate1Provider, uProvider);
  }

  @Override
  public void injectMembers(MainActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.petDelegate1 = petDelegate1Provider.get();
    instance.u = uProvider.get();
  }

....
}

create方法在实例化MembersInjector的同时把对象构造器赋值给它的二个成员变量,在方法injectMembers中,对象构造器把对象赋值给了MainActivity。下面我们找到injectMembers在哪调用的。这个流程就走完了。

回到DaggerMainComponent

 @Override
  public void inject(MainActivity mainActivity) {
    mainActivityMembersInjector.injectMembers(mainActivity);
  }
}

DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(this);
在这里调用了inject。
到此dagger基本用法就分析完了。


dagger2的进阶用法


1.单例模式
dagger2通过作用域控制对象是否单例。dagger2中有一个默认的@Singleton注解表示单例。单例注解也可以自定义,它的定义方式如下

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

加上@Scope表示这是约束单例作用域的注解,下面简称为Scope注解

Scope注解的用法
1.在Component中加入

@PreActivity
@Component(modules = MainModule.class)
public interface MainComponent {
    PetDelegate petDelegate();
    void inject(MainActivity mainActivity);
}

2.在module中需要单例的provide方法前面加入

@Module
public class MainModule {
    @PreActivity
    @Provides
    PetDelegate providePetDelegate(){
        return new DogAdapter();
    }
}

注:如果provide前面加入Scope注解而Component没有加入,则会出错,不能通过编译,反之虽然不会报错,但也没有效果。必须两边都加入才能起作用。
我们看看加了Scope注解后代码中的变化以及它的实现原理吧。

由于对象实例都是由对象创建工具提供的,我们直接来到DaggerMainComponent的initialize方法中,发现果然和之前不一样了

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

    this.providePetDelegateProvider =
        DoubleCheck.provider(MainModule_ProvidePetDelegateFactory.create(builder.mainModule));

    this.mainActivityMembersInjector =
        MainActivity_MembersInjector.create(providePetDelegateProvider, User1_Factory.create());
  }

之前没加Scope注解代码是这样的

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

    this.providePetDelegateProvider =
        MainModule_ProvidePetDelegateFactory.create(builder.mainModule);

    this.mainActivityMembersInjector =
        MainActivity_MembersInjector.create(providePetDelegateProvider, User1_Factory.create());
  }

对比一下,多出来一个DoubleCheck.provider,这个DoubleCheck是什么呢?
打开DoubleCheck,它的代码是这样的:

  public final class DoubleCheck<T> implements Provider<T>, Lazy<T> {
 private static final Object UNINITIALIZED = new Object();

  private volatile Provider<T> provider;
  private volatile Object instance = UNINITIALIZED;

  private DoubleCheck(Provider<T> provider) {
    assert provider != null;
    this.provider = provider;
  }

  @SuppressWarnings("unchecked") // cast only happens when result comes from the provider
  @Override
  public T get() {
    Object result = instance;
    if (result == UNINITIALIZED) {
      synchronized (this) {
        result = instance;
        if (result == UNINITIALIZED) {
          result = provider.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;
        }
      }
    }
    return (T) result;
  }


  public static <T> Provider<T> provider(Provider<T> delegate) {
    checkNotNull(delegate);
    if (delegate instanceof DoubleCheck) {
      return delegate;
    }
    return new DoubleCheck<T>(delegate);
  }


  }

DoubleCheck实现了Provider和Lazy接口,它可以作为Provider和Lazy对象。Lazy的作用下面会写,这里略过。
先看provider方法, MainActivity_MembersInjector实现了Factory接口,而Factory接口继承了Provider,在这里MainActivity_MembersInjector作为Provider而不是DoubleCheck类型,所以返回了
new DoubleCheck(delegate)。而DoubleCheck实现了Provider接口,所以它作为Provider类型可以赋值给providePetDelegateProvider,此时providePetDelegateProvider是一个DoubleCheck对象。
我们再看看DoubleCheck的get方法,很明显,它是一个单例模式,无论调用多少次,只会产生一个provider.get()对象。
provider.get()是什么呢,看看下面代码

  public final class MainModule_ProvidePetDelegateFactory implements Factory<PetDelegate> {
....

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

.....
}

上面也就是不使用Scope注解的providePetDelegateProvider的get方法,每get一次会new一个新对象,如果目标类有多个同类型的属性,使用Scope注解这些属性指向同一个地址,不使用则是每次get都new一下,指向不同的地址。


2.懒加载
懒加载就是在对象使用的时候再进行初始化
写法:
属性的写法

  @Inject
  protected Lazy<PetDelegate> petDelegate1;

调用对象的写法

   petDelegate1.get().feedPet()

下面我们看下源码,懒加载是如何实现的
先去看看对象创建工具

  private void initialize(final Builder builder) {

    this.providePetDelegateProvider =
        DoubleCheck.provider(MainModule_ProvidePetDelegateFactory.create(builder.mainModule));

    this.mainActivityMembersInjector =
        MainActivity_MembersInjector.create(providePetDelegateProvider, User1_Factory.create());
  }

啊喔,和没加lazy的没有区别,再去看注入的代码

 public void injectMembers(MainActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.petDelegate1 = DoubleCheck.lazy(petDelegate1Provider);
    instance.u = uProvider.get();
  }

这里发现生成对象的时候不是petDelegate1Provider.get()了,而是DoubleCheck.lazy(petDelegate1Provider),进去看看

  /** Returns a {@link Lazy} that caches the value from the given provider. */
  public static <T> Lazy<T> lazy(Provider<T> provider) {
    if (provider instanceof Lazy) {
      return lazy;
    }
    return new DoubleCheck<T>(checkNotNull(provider));
  }

原来返回的是DoubleCheck类型,难怪调用get才能获取真正的对象实例了。这里还有一点要说下,如果前面使用了Scope注解,那么传入的provider对象之前经过了DoubleCheck.provider的包装,成为了DoubleCheck对象,DoubleCheck对象实现了Lazy接口,于是返回的都是相同的对象,这里可以看出谷歌设计的精妙了。


3.Component依赖
Component写法

@UserScope
@Component(dependencies = MainComponent.class)
public interface TestdependComponent {
       void inject(DependComActivity dependComActivity);
}

注入时写法

DaggerTestdependComponent.builder().mainComponent(DaggerMainComponent.create()).build().inject(this);

看到代码我们可以发现DaggerTestdependComponent的内部bulid类保存了DaggerMainComponent的实例。它是在哪用的呢?看下DaggerTestdependComponent的源码

 private void initialize(final Builder builder) {

    this.petDelegateProvider =
        new Factory<PetDelegate>() {
          private final MainComponent mainComponent = builder.mainComponent;

          @Override
          public PetDelegate get() {
            return Preconditions.checkNotNull(
                mainComponent.petDelegate(),
                "Cannot return null from a non-@Nullable component method");
          }
        };
....
  }

原来petDelegateProvider创建了一个对象生成器,它的get方法通过调用mainComponent.petDelegate()来生成对象。这里的mainComponent就是DaggerMainComponent,因为DaggerMainComponent实现了MainComponent接口。点开DaggerMainComponent,看下mainComponent.petDelegate()干了什么。

  @Override
  public PetDelegate petDelegate() {
    return providePetDelegateProvider.get();
  }

这就回到了DaggerMainComponent之前分析过的部分了,真相大白。


4.@Subcomponent
Subcomponent我个人理解是Component依赖的另外一种写法。
父Component写法

@PreActivity
@Component(modules = MainModule.class)
public interface MainComponent {
    TestSubComponent testSubComponent();
    PetDelegate petDelegate();
    void inject(MainActivity mainActivity);
}

子Component写法

@UserScope
@Subcomponent(modules = UserModule.class)
public interface TestSubComponent {
    void inject(SubComActivity activity);
}

注入写法

DaggerMainComponent.create().testSubComponent().inject(this);

我们打开源码看看它和组件依赖的区别在哪

 private final class TestSubComponentImpl implements TestSubComponent {
    private final UserModule userModule;

    private Provider<User> provideUserProvider;

    private MembersInjector<SubComActivity> subComActivityMembersInjector;

    private TestSubComponentImpl() {
      this.userModule = new UserModule();
      initialize();
    }

    @SuppressWarnings("unchecked")
    private void initialize() {

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

      this.subComActivityMembersInjector =
          SubComActivity_MembersInjector.create(
              DaggerMainComponent.this.providePetDelegateProvider,
              provideUserProvider,
              User1_Factory.create());
    }

    @Override
    public void inject(SubComActivity activity) {
      subComActivityMembersInjector.injectMembers(activity);
    }
  }

原来Subcomponent在父component中是个内部类,值得注意的是, DaggerMainComponent.this.providePetDelegateProvider用的是父类的对象生成器,所以是否为单例依然由父类的Scope注解控制


到这里,dagger2的用法大致分析完了,不知道你懂没懂,反正我懂了。(^-^)。
最后还有一点,上面所有注入例子都没有传入module对象,是因为Component的Builder类中会在Component依赖的module对象没有传入的时候自动创建一个。但如果module对象带有参数,则要手动在注入时传入,否则会出现问题。

 public MainComponent build() {
      if (mainModule == null) {
        this.mainModule = new MainModule();
      }
      return new DaggerMainComponent(this);
    }

本人水平有限,如果有错漏的地方请不吝指点。本文为原创,欢迎转载,请转载时注明作者。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值