关于Dagger2
- Dagger基础用法
- 对注解的分类讲解——Inject部分
- 对注解的分类讲解——Module部分(一)
- 对注解的分类讲解——Component部分
- 对注解的分类讲解——Module(二)
- 对注解的分类讲解——Module(三)
- 对Dagger中几个类的说明
- Dagger-Android的使用
前言
本文将通过对注解的分类讲解来交代Dagger2的进阶用法。
关于Dagger的注解,简单将它们分成三类:
- Component部分
- Module部分
- Inject部分
来对应Dagger完成依赖注入的三部分内容,了解Dagger三部分最基本的那些使用方式,接下来来看看关于Module部分进阶的内容吧。
Module部分注解
@Binds
不同于@Provides注解,当参数和返回值类型相同时,将方法写成抽象方法,用Binds注解,这是一种简写,只能在返回值定义是抽象函数或是接口,具体返回值是具体的实现类时才能使用,举个例子:
// 定义一个抽象类
public abstract class AbsBindAnnotations {
public abstract void log();
public void logSelf() {
Log.d("Dagger测试", "获取到AbsBindAnnotations对象啦");
}
}
public class BindAnnotations extends AbsBindAnnotations {
// 需要在需要提供的对象的构造函数上加上@Inject注解
@Inject
public BindAnnotations() {}
@Override
public void log() {
Log.d("Dagger测试", "获取到了BindAnnotations对象");
}
}
接下来来创建Module类:
// 如果类中的方法是抽象方法,这个类也需要进行抽象化处理
@Module
public abstract class BindAnnotationsModule {
// 通过@Binds注解简化原有的提供方式
@Binds
abstract AbsBindAnnotations providerBindAnnotations(BindAnnotations bindAnnotations);
}
最后通过Component类来进行连接:
@Component(modules = BindAnnotationsModule.class)
public interface BindAnnotationsComponent {
void inject(BindAnnotationsActivity activity);
}
在Activity中进行调用:
public class BindAnnotationsActivity extends AppCompatActivity {
@Inject
BindAnnotations mBindAnnotations;
@Inject
AbsBindAnnotations mAbsBindAnnotations;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_bind_annotations);
DaggerBindAnnotationsComponent.create().inject(this);
mBindAnnotations.log();
mAbsBindAnnotations.logSelf();
}
}
通过这种方式就可以实现抽象方法的对象注入了,但是要注意的是,提供对象的方法必须要是抽象函数作为定义的返回值,而具体返回的值必须是抽象类的实现类:
@Binds
abstract AbsBindAnnotations providerBindAnnotations(BindAnnotations bindAnnotations);
这里要透露一个小秘密哦:抽象类换成接口可以的哦,很符合面向对象的编程方式,自己去尝试一下吧。
此外,当Binds和Provides两种注解同时出现在同一个Module中时需要做下处理,有两种方案可以选择:
- 最简单的方式就是将@Provides标示的方法设置成static
- 如果不使用static的话,那么就将所有的@Binds修饰的抽象方法移到一个抽象的Module中
举个例子(采用Binds和Provides两种注解并存解决办法其二):
public abstract class Factory {}
public class FactoryA extends Factory {}
public class FactoryB extends Factory {}
@Module
public abstract class AppModule {
@Singleton
@Binds
public abstract Factory bindsFactory(FactoryB factoryB);
@Singleton
@Provides
public static FactoryA providesFactoryA() {
return new FactoryA();
}
@Singleton
@Provides
public static FactoryB providesFactoryB() {
return new FactoryB();
}
}
@BindsOptionalOf
@BindsOptionalOf是为了注入Optional类型对象,关于Optional类型,Optional
这里来举一个例子吧,创建一个实体类:
public class OptionalAnnotations {
public void log() {
Log.d("Dagger测试", "获取到OptionalAnnotations对象");
}
}
通过@Binder的方式在Module中提供一个实例:
@Module
public abstract class OptionalAnnotationsModule {
// 使用了@BindsOptionalOf注解表明这是一个提供的可空类型数据
// 注意这里我没有传入任何参数,所以提供的对象应该是一个null的对象
@BindsOptionalOf
abstract OptionalAnnotations providerOptionalAnnotations();
}
最后通过Component进行连接:
@Component(modules = OptionalAnnotationsModule.class)
public interface OptionalAnnotationsComponent {
void inject(OptionalAnnotationsActivity activity);
}
在Activity中进行调用:
public class OptionalAnnotationsActivity extends AppCompatActivity {
// 注入对象,需要声明为Optio形式
@Inject
Optional mOptionalAnnotations;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_optional_annotations);
DaggerOptionalAnnotationsComponent.create().inject(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// 对对象的空值进行判断
if (mOptionalAnnotations.isPresent()) {
mOptionalAnnotations.get().log();
} else {
Log.d("Dagger测试", "获取到的OptionalAnnotations对象为空哦");
}
}
}
}
打印结果:
可以看到确实返回了为null,如果在提供对象的时候设置了返回的对象这里就可以获得不为null 的对象啦。
@Reusable
@Reusable注解的功能与@Singleton注解类似,两者不同点在于@Singleton注解是某种意义上的区域性的单例,而@Reusable注解只不过是为了简单复用而使用的一种方式,在多线程情况下@Reusable注解还是会产生多个对象不能保持单例的状态。
两个的区别在于构造过程中分别使用了DoubleCheck和SingleCheck,简单看一下它们的源码就知道它们的差别所在了:
SingleCheck
@Reusable注解所使用的是SingleCheck做检测:
public T get() {
Object local = instance;
if (local == UNINITIALIZED) {
Provider providerReference = provider;
if (providerReference == null) {
local = instance;
} else {
local = providerReference.get();
instance = local;
provider = null;
}
}
return (T) local;
}
DoubleCheck
@Singleton注解所使用的是DoubleCheck做检测:
public T get() {
Object result = instance;
if (result == UNINITIALIZED) {
synchronized (this) {
result = instance;
if (result == UNINITIALIZED) {
result = provider.get();
instance = reentrantCheck(instance, result);
provider = null;
}
}
}
return (T) result;
}
对单例模式熟悉的话,可以发现这两者区别在于对实例的检测方式,所以要使用@Reusable和@Singleton这两个注解的时候首先要分清楚使用的场景哦。