【Android】Dagger2从入门到再入门(进阶)

上一篇【Android】Dagger2从入门到再入门讲解了dagger2的基本使用方式,本篇介绍一下@Named,@Singleton,@Scope等其它注解的使用方式;

这里写图片描述

一.@Singleton

先看个例子:

1.我们在MainActivity里注入两个Student对象(接着上篇讲的,不明白的可以简单浏览下上一篇文章):

@Inject
Student student;

@Inject
Student studentTwo;

2.打印一下这两个对象:

tvOne = (TextView) findViewById(R.id.tv_one);
tvTwo = (TextView) findViewById(R.id.tv_two);
tvOne.setText(""+student);
tvTwo.setText(""+studentTwo);

3.结果:

这里写图片描述

嗯,记过很棒,确实是两个对象,但是我们如果想实现单例模式该怎么办呢,我们有时需要在不同的页面使用同一个实例,这时候@Singleton就能帮上忙了,@Singleton这个注解的作用就是声明单例模式,下面我们来验证一下:

4.StudentMoudle中提供Student实例的地方添加@Singleton注解:

@Module
public class StudentMoudle {

    @Singleton
    @Provides
    public Student provideIStudent()
    {
        Student student = new Student();
        student.setName("张三");
        student.setSayStr("一天不装逼,浑身难受");
        return student;
    }
}

5.在StudentComponent注入器类的上方添加@Singleton注解,然后编译运行:

@Singleton
@Component(modules = StudentMoudle.class)
public interface StudentComponent {
    void inject(MainActivity activity);
}

结果:

这里写图片描述

我们发现,确实实现了单例模式,是不是很简单;

这里写图片描述

二.@Named

再来看个例子:

1.我们在StudentMoudle中再添加一个提供Student实例的provideOtherStudent方法,如下:

@Module
public class StudentMoudle {

    @Singleton
    @Provides
    public Student provideIStudent()
    {
        Student student = new Student();
        student.setName("张三");
        student.setSayStr("一天不装逼,浑身难受");
        return student;
    }


    @Singleton
    @Provides
    public Student provideOtherStudent()
    {
        Student student = new Student();
        student.setName("李四");
        student.setSayStr("我是帅哥我怕谁");
        return student;
    }
}

此时编译的话,会报如下错误:

这里写图片描述

意思是说我们不能提供多个返回参数是一样实例的方法,因为dagger是根据返回类型来提供实例的,那么我们该怎么办呢?

2.这个时候就需要使用一个标记来指定需要使用哪个方法来提供实例,@Named就是干这个的了,我们加上@Named注解:

@Singleton
@Named("zhang")
@Provides
public Student provideIStudent()
{
    Student student = new Student();
    student.setName("张三");
    student.setSayStr("一天不装逼,浑身难受");
    return student;
 }


@Singleton
@Named("li")
@Provides
public Student provideOtherStudent()
{
    Student student = new Student();
    student.setName("李四");
    student.setSayStr("我是帅哥我怕谁");
    return student;
}

3.在注入的地方指定需要哪个对象,然后打印Student的名字:

@Inject
@Named("zhang")
Student student;

@Inject
@Named("li")
Student studentTwo;
tvOne = (TextView) findViewById(R.id.tv_one);
tvTwo = (TextView) findViewById(R.id.tv_two);
tvOne.setText(""+student+"--student name = "+student.getName());
tvTwo.setText(""+studentTwo+"--student name = "+studentTwo.getName());

结果如下,运行成功,分别创建了自己需要的对象:

这里写图片描述

这里说一下@Qulifier注解,@Qulifier功能和@Named一样,并且@Named就是使用@Qulifier来定义的,@Named的源码如下:

@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {

    /** The name. */
    String value() default "";
}

这下大家明白了吧,这个@Named可以随意定义,功能都是一样的,只是名字不同罢了,大家可以尝试下自己定义,然后使用方式和@Named一样,这里就不多说了;

三.@Scope

font size=”4” color=”#535346”>我们先来看下@Scope的源码:

/**
 * Identifies scope annotations. A scope annotation applies to a class
 * containing an injectable constructor and governs how the injector reuses
 * instances of the type. By default, if no scope annotation is present, the
 * injector creates an instance (by injecting the type's constructor), uses
 * the instance for one injection, and then forgets it. If a scope annotation
 * is present, the injector may retain the instance for possible reuse in a
 * later injection. If multiple threads can access a scoped instance, its
 * implementation should be thread safe. The implementation of the scope
 * itself is left up to the injector.
 */
@Target(ANNOTATION_TYPE)
@Retention(RUNTIME)
@Documented
public @interface Scope {}

→→ 源码里对Scope的解释比较多,这里我们留下了第一段话,就是上面的一大串英文,大概意思就是说,@Scope注解是标识作用域的,意思就是说你在@Provides处使用了@Scope相关联的注解,就必须在注入类使用同样的注解标识作用范围,另外如果使用了@Scope注解,实例的创建就是单例模式,如果不使用,每次都会创建一个新的对象,单例?说到这你应该想到了上面@Singleton注解,来看下@Singleton的源码:

/**
 * Identifies a type that the injector only instantiates once. Not inherited.
 *
 * @see javax.inject.Scope @Scope
 */
@Scope
@Documented
@Retention(RUNTIME)
public @interface Singleton {}

我们发现了@Scope的身影,这下明白了吧,@Singleton的单例其实是@Scope的作用,我们来看个简单的例子:

1.新建School类

public class School {

    private String schoolName;

    public School() {
    }

    public School(String schoolName) {
        this.schoolName = schoolName;
    }

    public String getSchoolName() {
        return schoolName;
    }

    public void setSchoolName(String schoolName) {
        this.schoolName = schoolName;
    }
}

2.自定义Scope注解

@Scope
@Retention(RUNTIME)
public @interface MainScope {
}

3.创建module和component,使用@MainScope注解

@Module
public class SchoolMoudle {

    @MainScope
    @Provides
    public School provideISchool()
    {
        School school = new School();
        school.setSchoolName("清华大学");
        return school;
    }

}
@Component(modules = SchoolMoudle.class)
@MainScope
public interface SchoolComponent {
    void inject(SecondActivity activity);
}

4.新建了SecondActivity,注入School对象,编译,运行

public class SecondActivity extends AppCompatActivity {

    private Button button;

    @Inject
    School school;

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

        initInject();
        initView();
    }

    private void initView() {
        button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(SecondActivity.this, "school name = "+school.getSchoolName(), Toast.LENGTH_SHORT).show();
            }
        });
    }

    private void initInject() {
        DaggerSchoolComponent.builder().schoolMoudle(new SchoolMoudle()).build().inject(this);
    }


}

结果:

这里写图片描述

注意:在同一个作用范围内,Provide方法提供的依赖对象就会变成单例,也就是说依赖需求方不管依赖几次Provide方法提供的依赖对象,Dagger2都只会调用一次这个方法;

这里写图片描述

参考连接:

1.Dagger2 入门

2.http://stackoverflow.com/questions/30260073/dagger-2-error-dependency-cannot-be-provided-without-an-inject-constructor-w

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值