在Dagger2 基础一种我们讲解了@Inject等四个基本的关键字。
在该章节种我们将讲解@Named关键字和Lazy类。
@Named
在依赖迷失时给出方向。
依赖迷失:在上面的代码的基础上,如果我在TeacherModule.java中定义两个返回值是String的方法。这种情况下,在依赖注入的时候Dagger2 这个时候就不知道注入哪一个了。这种情况就角依赖迷失。
示例:
// **************TeacherModule.java**************
@Module
public class TeacherModule {
@Provides
public String getTeacherName() {
return "HanMeimei";
}
@Provides
public String getTeacherAge() {
return "18";
}
}
// **************MainActivity.java**************
public class MainActivity extends AppCompatActivity {
@Inject String mName;
@Inject String mAge;
编译报错
E:\Sources\TestDagger2\app\src\main\java\com\example\testdagger2\ActivityComponent.java:7: ����: java.lang.String is bound multiple times:
void inject(MainActivity MainActivity);
^
@Provides String com.example.testdagger2.TeacherModule.getTeacherName()
@Provides String com.example.testdagger2.TeacherModule.getTeacherAge()
所以可以在TeacherModule的方法上添加上@Named关键字,同时在MainActivity的地方同样添加上关键字:
// **************TeacherModule.java**************
@Module
public class TeacherModule {
@Named("name")
@Provides
public String getTeacherName() {
return "HanMeimei";
}
@Named("age")
@Provides
public String getTeacherAge() {
return "18";
}
}
// **************MainActivity.java**************
public class MainActivity extends AppCompatActivity {
@Inject @Named("name") String mName;
@Inject @Named("age") String mAge;
这个时候再次查看编译出来的文件,就会发现已经生成了关于name和age的单独的TeachModule文件,同时在MainActvity和ActivityComponent生成的文件中也增加了新的变量,确认name和age。
编译文件如下:
//************MainActivity_MembersInjector.java************
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final Provider<ClassRoom> mClassRoomProvider;
private final Provider<Teacher> mTeacherProvider;
private final Provider<String> mNameProvider;
private final Provider<String> mAgeProvider;
public MainActivity_MembersInjector(
Provider<ClassRoom> mClassRoomProvider,
Provider<Teacher> mTeacherProvider,
Provider<String> mNameProvider,
Provider<String> mAgeProvider) {
assert mClassRoomProvider != null;
this.mClassRoomProvider = mClassRoomProvider;
assert mTeacherProvider != null;
this.mTeacherProvider = mTeacherProvider;
assert mNameProvider != null;
this.mNameProvider = mNameProvider;
assert mAgeProvider != null;
this.mAgeProvider = mAgeProvider;
}
public static MembersInjector<MainActivity> create(
Provider<ClassRoom> mClassRoomProvider,
Provider<Teacher> mTeacherProvider,
Provider<String> mNameProvider,
Provider<String> mAgeProvider) {
return new MainActivity_MembersInjector(
mClassRoomProvider, mTeacherProvider, mNameProvider, mAgeProvider);
}
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.mClassRoom = mClassRoomProvider.get();
instance.mTeacher = mTeacherProvider.get();
instance.mName = mNameProvider.get();
instance.mAge = mAgeProvider.get();
}
public static void injectMClassRoom(
MainActivity instance, Provider<ClassRoom> mClassRoomProvider) {
instance.mClassRoom = mClassRoomProvider.get();
}
public static void injectMTeacher(MainActivity instance, Provider<Teacher> mTeacherProvider) {
instance.mTeacher = mTeacherProvider.get();
}
public static void injectMName(MainActivity instance, Provider<String> mNameProvider) {
instance.mName = mNameProvider.get();
}
public static void injectMAge(MainActivity instance, Provider<String> mAgeProvider) {
instance.mAge = mAgeProvider.get();
}
}
//**************DaggerActivityComponent.java**************
@Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class DaggerActivityComponent implements ActivityComponent {
private Provider<Teacher> getTeacherProvider;
private Provider<String> getTeacherNameProvider;
private Provider<String> getTeacherAgeProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private DaggerActivityComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static ActivityComponent create() {
return builder().build();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.getTeacherProvider = TeacherModule_GetTeacherFactory.create(builder.teacherModule);
this.getTeacherNameProvider = TeacherModule_GetTeacherNameFactory.create(builder.teacherModule);
this.getTeacherAgeProvider = TeacherModule_GetTeacherAgeFactory.create(builder.teacherModule);
this.mainActivityMembersInjector =
MainActivity_MembersInjector.create(
ClassRoom_Factory.create(),
getTeacherProvider,
getTeacherNameProvider,
getTeacherAgeProvider);
}
@Override
public void inject(MainActivity MainActivity) {
mainActivityMembersInjector.injectMembers(MainActivity);
}
public static final class Builder {
private TeacherModule teacherModule;
private Builder() {}
public ActivityComponent build() {
if (teacherModule == null) {
this.teacherModule = new TeacherModule();
}
return new DaggerActivityComponent(this);
}
public Builder teacherModule(TeacherModule teacherModule) {
this.teacherModule = Preconditions.checkNotNull(teacherModule);
return this;
}
}
}
//************TeacherModule_GetTeacherAgeFactory.java************
......
//************TeacherModule_GetTeacherNameFactory.java************
......
```
所以这个时候,我们直接调用mName和mAge对象的时候,程序可以正确的知道你想调用的是哪个对象。
@Qualifier
该关键字的作用其实跟@Named是一样的,其实应该说@Named就是一种已经封装好的@Qualifier。毕竟@Named的代码如下:
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Named {
/** The name. */
String value() default "";
}
那么我们为什么还需要@Qualifier呢?通过@Qualifier我们可以自定义注解,非常简单的例子,比如我有两个老师,我可以把Name归为一类,把Age再归为另一类,这样代码看起来非常的清晰。
示例:
//首先,先定义一个自定义的注解Age
// ******************Age.java***************
package com.example.testdagger2;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import javax.inject.Qualifier;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Qualifier
@Documented
@Retention(RUNTIME)
public @interface Age {
/** The age. */
String value() default "";
}
//然后修正我们的TeacherModule
@Module
public class TeacherModule {
@Named("name1")
@Provides
public String getTeacherName() {
return "HanMeimei";
}
@Age("age1")
@Provides
public String getTeacherAge() {
return "18";
}
@Named("name2")
@Provides
public String getOtherTeacherName() {
return "Lilei";
}
@Age("age2")
@Provides
public String getOtherTeacherAge() {
return "20";
}
}
//再修正我们的调用类MainActivity
@Inject @Named("name1") String mName;
@Inject @Age("age1") String mAge;
@Inject @Named("name2") String mName2;
@Inject @Age("age2") String mAge2;
这样我们就可以跟@Named一样解决依赖注入迷失的问题的。而且对变量也进行了归类,代码可读性大大提升。
Lazy
Lazy 等同于注入T,只是只有在你get它的时候,才会真正的生成T。也就是说当你第一次去get时,它才会去初始化这个实例。并且多次调用get方法,返回的是同一个对象T。通过Lazy的这种方式,我们就可以在真正需要加载View或者调用数据等等情况下才去获取对象,从而缩短应用初始化的时间,提升性能。
代码示例:
public class MainActivity extends AppCompatActivity {
private TextView mTextView;
@Inject Teacher mTeacher;
@Inject Lazy<Teacher> mTeacher2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerActivityComponent.create().inject(this);
mTextView = (TextView) findViewById(R.id.text);
mTextView.setText(mTeacher.getTeacher1() + "\n" +mTeacher2.get().getTeacher2() + "\n" + mTeacher2.get() + "\n" + mTeacher2.get());
}
}
通过上面的代码,mTeacher可以直接获取到Teacher类的函数;而mTeacher2的话,必须通过get()方法获取到Teacher的实例之后,才能获取到函数。这说明Lazy这种方式只有在get它的时候,才会真正的生成对象。并且根据代码执行的结果,多次调用get()方法,返回的是同一个对象。
通过上面的讲解,我们可以通过@Named来区分多个返回值一样的函数,简洁代码。而Lazy可以帮助我们缩短类初始化的时候,提升性能。