Dagger2的使用

 

 

想学习下Dagger2 ,搜了很多资料但都是附带着RxJava等其他东西,让楼主学习起来比较费时(可能比较笨),本人也没有使用过Dagger1.x,所以学习Dagger2的更是举步维艰啊。 

看了很多资料,终于懂了一点,下面主要说说Dagger2的使用过程及自己见解,加深印象。说的不对的也请读者指正。

 

Dagger2是Android的一个依赖注入框架,可用于模块间解耦,提高代码的健壮性和可维护性。

Dagger2是基于一个有向无环图结构的依赖注入库,因此dagger2的使用过程中不能出现循环依赖的现象。

以下都已 Android studio开发工具为例。

一、引用

在module的build.gradle添加如下两个模块 :

a、apply plugin: 'com.neenbedankt.android-apt'

b、compile 'com.google.dagger:dagger:2.5'

compile 'com.google.dagger:dagger-compiler:2.5'

在project的build.gradle中dependencies 添加

classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'

如:

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.4'
    }
}
apt相关的依赖一定要加上,要不生成不了对应所需文件 Dagger+"" 等。

2、Component和Module  

Dagger2 通过注解来工作,定义不同的角色,主要的注解包括:@Component 、@Module 、@Inject、@Provides 、@Scope 、@SubComponent 等。

Component和Module是Dagger2的两个主要注解。

module是生产对象的地方,即是生产方,需要什么样的对象都要在这里生产

Component 是联系module和module使用场景的桥梁,module生产的对象需要在哪里使用要靠Component来提供、暴露,即提供方。使module和module的使用场景达到了一个解耦。

dagger2的使用

模拟一个场景,类A需要在DaggerActivity使用 。

正常情况:

A类 :

public class A {

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

DaggerActivity :

public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivityComponent aComponenet = DaggerActivityComponent.builder()
                .aModule(new AModule())
                .build();
        A a = new A();
        a.setAge(10);
        Log.d(TAG, "onCreate --> a.getAge() : : " + a.getAge());  a.setAge();   

    }
}

使用Dagger2:

A类 :

public class A {

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

增加一个Module , AModule类 :

@Module
public class AModule {


    @Provides
    A provideA() {
        return new A();
    }
}

Module 类需要使用@Module注解,标记这是一个生产对象的地方,这里仅生产了对象 A。

增加一个Component ,AComponent类 :

@Component(modules = AModule.class)
public interface AComponent{

    A a();
}

Component类需要使用@Component注解,并添加modules依赖,标记提供哪些对象,为哪些Module提供桥梁 。modules可以提供多个,写法是 modules = {AModule.class,A2Module.class}等。Component也可以依赖其它Component,实现@Component(dependencies = {A2Component.class,A3Component.class} modules = {AModule.class, A2Module.class})

使用,DaggerActivity :

public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        AComponentaComponenet = DaggerAComponent.builder()
                .aModule(new AModule())
                .build();

        A a = aComponenet.a();
        a.setAge(10);

       
    }
}

这样就基本实现了Dagger2的使用,但我们发现这时并没有达到很好的解耦效果。下面再介绍两种优化 :

使用Dagger2  二 :

使用@Inject注解 

A2 类 :

public class A2 {
    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

基本没变化 

A2Module :

@Module
public class A2Module {

    @Provides
    A2 povideA2() {
        return new A2();
    }

}

A2Component :

@Component(modules = A2Module.class)
public interface A2Component {
    void inject(DaggerActivity mainActivity);
}

这里多了一个inject()方法,参数为提供A2实例的地方,即使用场景。相比AComponent主动暴露A实例的方式,解耦了一些。

使用

DaggerActivity  :

public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";

    @Inject
    A2 aaa2;

 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    

        DaggerA2Component.builder()
                .a2Module(new A2Module())
                .build()
                .inject(this);


        aaa2.setAge(20);
        aaa2.getAge();
        Log.d(TAG, "onCreate --> aaa2.getAge() : : " + aaa2.getAge());

      
    }
}

这里看到 通过@Inject 注解来能达到实例化 A2对象的目的。DaggerA2Component的inject()就是告诉Dagger2在哪里实例化A2对象,这里是在DaggerActivity,并将对象赋给aaa2引用。 解耦更彻底了一些 。

还能更简化一些吗 ??   

Dagger2   三 :

A3类 :

public class A3 {

    @Inject
    public A3() {
    }

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

注意这里 在A3的构造函数上使用了 @Inject注解 。

A3Module 可以没有 

那么 A3Component也就没有了。 .(没有桥头,要桥梁干么呢)

使用  DaggerActivity 

public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";


    @Inject
    A3 aaa3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        aaa3.setAge(30);
        aaa3.getAge();
        Log.d(TAG, "onCreate --> aaa3.getAge() : : " + aaa3.getAge());

    }
}

这里A3的初始化通过@Inject注解来实现,但并没有通过Component来告诉Dagger2在哪里实例化A3并赋值给谁。 这主要依赖在A3的构造函数中添加了@Inject注解,当需要实例化一个@Inject注解的对象时,就去遍历来实例化对应的对象。

这样解耦工作完全实现了。

看完示例三,可以发现Dagger2的优势完全体现出来了吧。

通过上面的实例可以发现示例三比示例二更简洁,那么Module注解是不是可以不要了呢 ? 

什么时候使用Module,什么时候使用@Inject

一般系统的 、SDK的、第三方库提供的对象用Module   (你没法在人家的构造函数上添加@Inject啊)

自定义的对象用Inject    定义一个子类继承系统、SDK、第三方库的对象,这时也可以使用Inject。

Component间的依赖 

依赖一个Component时父Component需要将提供的对象暴露出来,否则子Component获取不到

@Component(modules = {AModule.class, A2Module.class})
public interface AComponent {

    A a();
}
@Component(dependencies = AComponent.class, modules = A2Module.class)
public interface A2Component {
    void inject(DaggerActivity mainActivity);
}

AComponent暴露了A对象,这样A2Component才能获取到A。

@Scope注解

这个注解是用来划分作用域的(在哪儿使用,使用范围),意思是画出一块区域来,生产的东西如果限定在此作用域,那都放到这里,作用域的场景类(如Activity、Fragment、Application)如果需要这个实例,就来这个作用域来取,有就直接使用,没有就先创建,放到作用域供下次使用。

dagger2自已有个@Scope注解,叫@Singleton,就是大家都熟悉的单例模式

可以自定义@Scope注解,比如限定生产出的某个对象只能在Activity中、Application中使用、Fragment中使用等等。。

定义一个Activity作用域的注解 

@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface PerActivity {
}
PerActivity的使用

public class A2 {

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

public class A3 {

    @Inject
    public A3() {
    }

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}


public class A4 {

    @Inject
    public A4() {
    }

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

 

@Module
public class A2Module {

    @Named("李四")
    @Provides
    A2 povideALisi() {
        return new A2(21);
    }

    @Named("张三")
    @Provides
    A2 povideAZhangSan() {
        return new A2(25);
    }

    @PerActivity
    @Provides
    A4 provideA4() {
        return new A4();
    }

    @Provides
    A3 provideA3() {
        return new A3();
    }

}

注意这里只给 provideA4()方法添加了@PerActivity注解 。

@PerActivity
@Component(dependencies = ActivityComponent.class, modules = A2Module.class)
public interface A2Component {
    void inject(DaggerActivity mainActivity);
}

 依赖A2Module的对应Component也要添加@PerActivity注解。

public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";

    @Inject
    A4 aaa4;

    @Inject
    A4 testa4;

    private Button nextBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.dagger_layout);

        DaggerA2Component.builder()
                .a2Module(new A2Module())
                .build()
                .inject(this);
    

        aaa4.setAge(30);
        Log.d(TAG, "onCreate --> aaa4.getAge() : : " + aaa4.getAge());
        Log.d(TAG, "onCreate --> testa4.getAge() : : " + testa4.getAge());

        testa4.setAge(50);

        Log.d(TAG, "onCreate --> 2 aaa4.getAge() : : " + aaa4.getAge());
        Log.d(TAG, "onCreate --> 2 testa4.getAge() : : " + testa4.getAge());
        Log.d(TAG, "onCreate ------------------------------------------>  : ");

    }
}

可以发现这时aaa4和testa4两个对象会相互影响,改变一个,另一个也被修改,其实为同一个对象,为什么会这样呢?? 

我们来看下Dagger2自动生成的DaggerA2Component类(这里只捡主要代码粘贴):

public final class DaggerA2Component implements A2Component {
    private Provider<A2> povideAZhangSanProvider;
    private Provider<A2> povideALisiProvider;
    private Provider<A3> provideA3Provider;
    private Provider<A4> provideA4Provider;
    private MembersInjector<DaggerActivity> daggerActivityMembersInjector;

    private DaggerA2Component(DaggerA2Component.Builder builder) {
        assert builder != null;

        this.initialize(builder);
    }

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

    public static A2Component create() {
        return builder().build();
    }

    private void initialize(DaggerA2Component.Builder builder) {
        this.povideAZhangSanProvider = A2Module_PovideAZhangSanFactory.create(builder.a2Module);
        this.povideALisiProvider = A2Module_PovideALisiFactory.create(builder.a2Module);
        this.provideA3Provider = A2Module_ProvideA3Factory.create(builder.a2Module);
        this.provideA4Provider = ScopedProvider.create(A2Module_ProvideA4Factory.create(builder.a2Module));
        this.daggerActivityMembersInjector = DaggerActivity_MembersInjector.create(MembersInjectors.noOp(), this.povideAZhangSanProvider, this.povideALisiProvider, this.provideA3Provider, this.provideA4Provider);
    }

    public void inject(DaggerActivity mainActivity) {
        this.daggerActivityMembersInjector.injectMembers(mainActivity);
    }

   
}

可以看到对于A2Module里的四个被@Provides注解的方法,DaggerA2Component生成了四个Provider对象,

    private Provider<A2> povideAZhangSanProvider;
    private Provider<A2> povideALisiProvider;
    private Provider<A3> provideA3Provider;
    private Provider<A4> provideA4Provider;

而这四个对象的创建时重点 ,在initialize()方法中,可以发现前三个对象的创建都是xx_Factory.create()方式,而使用@PerActivity注解的provideA4Provider则是ScopedProvider.create()创建,区别就在这里了,Factory工厂模式创建的对象每次都是新建的对象,而ScopedProvider则可以返回上次创建的对象,起到了单例的作用。

具体可看ScopedProvider类

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

  private final Factory<T> factory;
  private volatile Object instance = UNINITIALIZED;

  private ScopedProvider(Factory<T> factory) {
    assert factory != null;
    this.factory = factory;
  }

  @SuppressWarnings("unchecked") // cast only happens when result comes from the factory
  @Override
  public T get() {
    // double-check idiom from EJ2: Item 71
    Object result = instance;
    if (result == UNINITIALIZED) {
      synchronized (this) {
        result = instance;
        if (result == UNINITIALIZED) {
          instance = result = factory.get();
        }
      }
    }
    return (T) result;
  }

  /** Returns a new scoped provider for the given factory. */
  public static <T> Provider<T> create(Factory<T> factory) {
    if (factory == null) {
      throw new NullPointerException();
    }
    return new ScopedProvider<T>(factory);
  }
}

可以看到 T get()方法取A4对象时,使用了单例方法,如果已被创建则直接返回。

子Component

子Component跟前面的一个Component依赖另一个Component有点像,区别是子Component可以获取到父Component的所有可以生产出的对象,而Component依赖则只能获取到被依赖的Component所暴露出来的可以生产的对象。

A4 类:
public class A4 {

    @Inject
    public A4() {
    }

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
@Component(dependencies = AComponent.class, modules = A2Module.class)
public interface A2Component {
    void inject(DaggerActivity mainActivity);

    A4Component plus(A4Module module1); // //参数为A4Component依赖的Module
}
@Subcomponent(modules = A4Module.class)
public interface A4Component {
    void inject(DaggerActivity mainActivity);
}
DaggerActivity 
public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";

    @Inject
    A2 aaa2;

    @Inject
    A4 aaa4;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        DaggerA2Component.builder()
                .a2Module(new A2Module())
                .build()
                .plus(new A4Module())
                .inject(this);


        aaa2.setAge(20);
        aaa2.getAge();
        Log.d(TAG, "onCreate --> aaa2.getAge() : : " + aaa2.getAge());

        aaa4.setAge(30);
        aaa4.getAge();
        Log.d(TAG, "onCreate --> aaa4.getAge() : : " + aaa4.getAge());

        Log.d(TAG, "onCreate ------------------------------------------>  : ");

    }
}

可以看到  A4在这里也可以正常使用。

@Named注解


这个注解是用来设置别名的,用来区分同一个类型的不同对象。比如我们都知道Android 中的Context有两种,一种是全局的,一种是Activity中的,为了区分他们,我们就可以加上别名;又比如有一个Person类,他有两个实例,一个是张三,一个是李四,我们也可以用别名区分他们。

A2 类 :

public class A2 {

    public A2(int age) {
        this.age = age;
    }

    public A2() {
    }

    private int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

A2Module :

@Module
public class A2Module {

    @Named("李四")
    @Provides
    A2 povideA2() {
        return new A2(21);
    }

    @Named("张三")
    @Provides
    A2 povideA21() {
        return new A2(25);
    }

}

使用 :

public class DaggerActivity extends Activity {

    private static final String TAG = "DaggerActivity";

    @Named("张三")
    @Inject
    A2 aaa2;

    @Named("李四")
    @Inject
    A2 aaa2_lisi;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
       
        DaggerA2Component.builder()
                .a2Module(new A2Module())
                .build()
                .inject(this);

        Log.d(TAG, "onCreate --> aaa2.getAge() : : " + aaa2.getAge());
        Log.d(TAG, "onCreate --> aaa2_lisi.getAge() : : " + aaa2_lisi.getAge());

    }
}

大体就写到这里了 。。。。

 

参考文档 : 

http://www.2cto.com/kf/201604/499397.html

http://www.cnblogs.com/zhuyp1015/p/5119727.html

http://blog.csdn.net/duo2005duo/article/details/50696166

http://www.cnblogs.com/tiantianbyconan/archive/2016/01/02/5095426.html

 

 

 

 

转载于:https://my.oschina.net/u/559847/blog/705203

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值