您的位置:首页 > 移动开发 > Android开发

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

2016-12-11 14:54 375 查看
上一篇【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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: