dagger2学习笔记

1.导入Dagger2
project的build.gradle中

buildscript {

    ....

    dependencies {

        classpath 'com.android.tools.build:gradle:2.1.0'
        // 添加android-apt 插件
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }
}

app的build.gradle中

apply plugin: 'com.android.application'
// 应用插件
apply plugin: 'com.neenbedankt.android-apt'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.mahao.alex.architecture"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}


dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'

    // dagger 2 的配置
    compile 'com.google.dagger:dagger:2.4'
    apt 'com.google.dagger:dagger-compiler:2.4'
    compile 'org.glassfish:javax.annotation:10.0-b28'// 添加java 注解库
}

android-apt是Gradle编译器的插件,主要两个作用:

  • 编译时使用该工具,最终打包时不会将该插件打入到apk中。
  • 能够根据设置的源路径,在编译时期生成相应代码。

2.Dagger2 API

public @interface Component {
    Class[] modules() default {};
    Class[] dependencies() default {};
}

public @interface Subcomponent {
    Class[] modules() default {};
}

public @interface Module {
    Class[] includes() default {};
}

public @interface Provides {
}

public @interface MapKey {
    boolean unwrapValue() default true;
}

public interface Lazy {
    T get();
}

用在dagger2中的 JSR-330(Java中的依赖注入标准)定义的注解

public @interface Inject {
}

public @interface Scope {
}

public @interface Qualifier {
}

3.dagger2 使用
3.1 @inject使用

http://blog.csdn.net/lisdye2/article/details/51942511
方式一:由module中@Provides 注解的providerXXX()提供对象

public class Person {  
   person(){
  }
}
@Module   //依赖对象提供者
public class ActivityModule{
 private SplashActivity activity;

    public ActivityModule(SplashActivity activity) {
        this.activity = activity;
    }
    @Provides // 关键字,标记具体提供依赖对象的方法
    SplashActivity providerSplashActivity  (){
        return activity;
    }
    @Provides // 关键字,标记具体提供依赖对象的方法
    Person providerPerson(){
        return new Person();
    }
}
@Component(modules = ActivityModule.class)
public interface ActivityComponent {
    void inject(SplashActivity splashActivity );
}

到这重新build项目, AndroidStudio -> Build -> Make Project,生成
DaggerXXXComponent。

public class SplashActivity extends AppCompatActivity {

    @Inject
    Person person;

    @Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);
       //开始注入
      DaggerActivityComponent.builder()
    .ActivityModule(new ActivityModule())
    .build()
    .inject(this);
    }
}

方式二:@Inject注解类(Person )的构造函数,直接初始化对象

public class Person {  
   @inject //@Inject注解构造函数
   person(){
  }
}
@Module   //依赖对象提供者
public class ActivityModule{
 private SplashActivity activity;

    public ActivityModule(SplashActivity activity) {
        this.activity = activity;
    }
    @Provides // 关键字,标记具体提供依赖对象的方法
    SplashActivity providerSplashActivity  (){
        return activity;
    }
}
//记得先rebuild 项目
public class SplashActivity extends AppCompatActivity {

    @Inject
    Person person;

    @Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);
       //开始注入
      DaggerActivityComponent.builder()
    .ActivityModule(new ActivityModule())
    .build()
    .inject(this);
    }
}

需要参数的实例化对象

public class Person {  
   String name;
   person(String name){
   this.name=name;
  }
}

ActivityModule:
@Module   //依赖对象提供者
public class ActivityModule{
 private SplashActivity activity;

    public ActivityModule(SplashActivity activity) {
        this.activity = activity;
    }
    @Provides // 关键字,标记具体提供依赖对象的方法
    SplashActivity providerSplashActivity  (){
        return activity;
    }
    @Provides // name由ActivityModule中providerString提供
    Person providerPerson(String name){
        return new Person(name);
    }
    @Provides // 关键字,标记具体提供依赖对象的方法
    String providerString(){
        return "李好";
    }
}

//记得先rebuild 项目
public class SplashActivity extends AppCompatActivity {

    @Inject
    Person person;

    @Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);
       //开始注入
      DaggerActivityComponent.builder()
    .ActivityModule(new ActivityModule())
    .build()
    .inject(this);
    }
}

注入流程
步骤1:查找Module中是否存在提供对象(@Inject标记的对象)的方法。
步骤2:若Module中存在提供该对象的方法(providerXXX),查看该方法是否有参数
步骤2.1:若有参数,则按从步骤1开始依次初始化每个参数(即从(Module的providerXXX)中获取参数值)。
步骤2.2:若没有参数,则直接调用初始化该类实例,一次依赖注入结束。
步骤3:若Module中没有提供该对象方法,则查找@Inject注解的构造函数,看构造函数是否有参数
步骤3.1:若有参数,则从步骤1开始依次初始化每个参数
步骤3.2:若没有参数,则直接初始化该类实例,一次依赖注入结束。

3.2 @Qualifier
使用场景:
当一个类有两个构造函数时,使用Dagger2时,如何获取指定构造函数new出来的对象 ? 这就需要@Qualifier来解决。

public class Person {  
   String name;
   person(){
   }

   person(String name){
   this.name=name;
  }
}

首先
用@Qualifier 自定义一个限定符

@Qualifier//限定符
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Type {
    String value() default "";//默认值为""
}

修改ActivityModule, 添加@Named;

@Module   //依赖对象提供者
public class ActivityModule{
 private SplashActivity activity;

    public ActivityModule(SplashActivity activity) {
        this.activity = activity;
    }
    @Provides // 关键字,标记具体提供依赖对象的方法
    SplashActivity providerSplashActivity  (){
        return activity;
    }
    @Named("normal")
    @Provides // 关键字,标记具体提供依赖对象的方法
    Person providerPerson(String name){
        return new Person(name);
    }
    @Named("default")
    @Provides // 关键字,标记具体提供依赖对象的方法
    Person providerPerson(){
        return new Person();
    }

 @Provides
    public String provideString(){
        return new String(“有参数”);
    }
}

修改SplashActivity , 添加@Type;

public class SplashActivity extends AppCompatActivity {
    @Named("default")   
    @Inject
    Person person;

    @Named("normal")
    @Inject
    Person person2;
    @Override
    protected void onCreate(Bundle bundle) {
        super.onCreate(bundle);
       //开始注入
      DaggerActivityComponent.builder()
    .ActivityModule(new ActivityModule())
    .build()
    .inject(this);
     Log.i("dagger","person.name = "+ person.name+"; person2.name = "+ person2.name);
    }
}

打印结果

person.name = null; person2.name=“有参数”

此时的person,person2是由不同的构造方法创建。
通过字符串标记一个对象,容易导致前后不匹配.做如下修改


@Qualifier  // 关键词
@Retention(RetentionPolicy.RUNTIME)  // 运行时仍可用
public @interface PersonForDefault {

}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface PersonForName {
    // name 对象的注解
}
**********************ActivityModule**********************
    @PersonForDefault 
    @Provides // 关键字,标记具体提供依赖对象的方法
    Person providerPerson(String name){
        return new Person(name);
    }
    @PersonForName 
    @Provides // 关键字,标记具体提供依赖对象的方法
    Person providerPerson(){
        return new Person();
    }

 @Provides
    public String provideString(){
        return new String(“有参数”);
    }
********************SplashActivity*************************
    @PersonForDefault   
    @Inject
    Person person;

    @PersonForName 
    @Inject
    Person person2;

3.3 @Singleton
@Singleton注解实际上实现的是一个全局单例模式,通过@Singleton创建出来的全局单例并不保持在静态域上,而是保留在Component实例中。不同的Component实例对象通过@Singleton创建出来的全局单例不同。

  • 不使用 @Singleton
public class SplashActivity extends AppCompatActivity{

    @Inject
    Person person;

    @Inject
    Person person2;

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

        // 构造桥梁对象
 ActivityComponent splashcomponent=  DaggerActivityComponent.builder()
    .ActivityModule(new ActivityModule())
    .build();

        //注入
        component.inject(this);

        // 打印两个对象的地址
        Log.i("dagger","person = "+ person.toString()+"; person2 = "+ person2.toString());
    }
}

打印结果

 person = com.nihao.dagger2.Person@430d1620;
 person2 = com.nihao.dagger2.Person@430d17c8;

person 和person2 地址不相等,不是同一个对象,即创建了2个对象。

  • 使用 @Singleton

修改ActivityModule代码,在providerPerson()上添加 @Singleton注解

@Module   //依赖对象提供者
public class ActivityModule{
 private SplashActivity activity;

    public ActivityModule(SplashActivity activity) {
        this.activity = activity;
    }
    @Provides // 关键字,标记具体提供依赖对象的方法
    SplashActivity providerSplashActivity (){
        return activity;
    }

    @Singleton
    @Provides // 关键字,标记具体提供依赖对象的方法
    Person providerPerson(){
        return new Person();
    }
}

ActivityComponent 也要添加@Singleton,否则无法编译

@Singleton
@Component(modules = ActivityModule.class)
public interface ActivityComponent {
    void inject(SplashActivity splashActivity );
}

重新运行

person = com.mahao.alex.architecture.dagger2.Person@4310f898;          person2= com.mahao.alex.architecture.dagger2.Person@4310f898;

person 和person2 地址相等,是由splashcomponent提供同一个对象。

  • @Singleton创建出来的全局单例并不保持在静态域上,而是保留在Component实例中
**********************修改ActivityComponent **************
@Singleton
@Component(modules = ActivityModule.class)
public interface ActivityComponent {
    void inject(SplashActivity splashActivity );
    void inject(MainActivity mainActivity );
}
*******************ActivityModule添加***********************
MainActivity mainactivity;
    public ActivityModule(MainActivity mainactivity) {
        this.mainactivity= mainactivity;
    }
    @Provides // 关键字,标记具体提供依赖对象的方法
    MainActivity providerMainActivity  (){
        return mainactivity;
    }
*******************添加MainActivity ***********************  
public class MainActivity extends AppCompatActivity{

    @Inject
    Person person3;

    @Inject
    Person person4;

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

        // 构造桥梁对象
 ActivityComponent maincomponent=  DaggerActivityComponent.builder()
    .ActivityModule(new ActivityModule())
    .build();

        //注入
        maincomponent.inject(this);

        // 打印两个对象的地址
        Log.i("dagger","person3 = "+ person3.toString()+"; person4 = "+ person4.toString());
    }
}

此时person 和person2 是由splashcomponent提供同一个对象。
person3和person4是由maincomponent提供的同一对象,但是person
和person3,person4不是同一对象 ,这是因为maincomponent和splashcomponent不是同一个对象。

3.4@MapKey

这个注解用于定义依赖集合(映射和集)。
定义

 @MapKey(unwrapValue = true)
@interface TestKey {
    String value();
}

提供依赖

@Provides(type = Type.MAP)
@TestKey("foo")
String provideFooKey() {
    return "foo value";
}

@Provides(type = Type.MAP)
@TestKey("bar")
String provideBarKey() {
    return "bar value";
}

使用

@Inject
Map<String, String> map;

map.toString() // => „{foo=foo value, bar=bar value}”

3.5 Lazy

@Inject
Lazy lazyPerson; // 注入Lazy元素
@Inject
Provider providerPerson; // 注入Provider

 // 调用该方法时才会去创建Person,以后每次调用获取的是同一个对象
 Person person = lazyPerson.get();
 Person person1 = lazyPerson.get();
 person1,person指向同一对象 ;

// 调用该方法时才回去创建Person1,以后每次调用都会重新加载Module中的具体方法,根据Module中的实现,可能相同,可能不相同。
Person person2 = providerPerson.get();
Person person3 = providerPerson.get();
person2 和person3 可能相同,可能不相同。

3.6 Component依赖
Component之间的关系有: 依赖(dependencies),包含(SubComponent),继承方式(extends)

http://blog.csdn.net/soslinken/article/details/70231089

经验总结:

  • @Inject成员不能是private的,否则会报:Error:(35, 29) 错误: Dagger does not support injection into private fields
  • @Provides的优先级高于@Inject
  • @Provides注解的方法以ProvidesXXX形式规范
  • 通过Singleton创建出来的单例并不保持在静态域上,而是保留在Component实例中。
  • @Component关联的@Module中的任何一个@Provides有@scope,则该整个@Component要加上这个scope。否则在暴露或者注入时(不暴露且不注入时,既不使用它构造对象时,不报错),会报错。
  • 没有scope的组件不能依赖有scope的组件。否则会报错。
  • @Component的dependencies与@Component自身的scope不能相同,即组件之间的scope不能相同,否则出现错误。
  • @Singleton的组件不能依赖其他scope的组件,但是其他scope的组件可以依赖@Singleton组件。
  • 一个组件不能同时有多个scope即一个 组件依赖多个Component(Subcomponent除外)时报错:Component
    depends on more than one scoped component

你可能感兴趣的:(android)