主要注解
javax.inject包
- @Inject
- @Scope和@Singleton
- @Named和@Qualifier
dagger包
- @Module和@Provides
- @Component
- @Subcomponent
- Lazy:非注解类,用于延迟注入
注解使用
@Inject注解
用于标记需要注入的依赖,或者标记用于提供依赖的构造方法。
在Dagger2中@Inject有3种使用形式:
1、构造器注入,@Inject标注在构造器上:
- 告诉Dagger2可以使用这个构造器构建对象。
- 注入构造器所需要的参数的依赖。
构造器注入的局限:
- 如果有多个构造器,我们只能标注其中一个,无法标注多个。
- 如果需要注入第三方类库中类对象,无法完成注入。
例如:
public class Engine {
@Inject
public Engine() {}
}
public class Car {
private Engine engine;
@Inject
public Car(Engine engine) {
this.engine = engine;
}
}
2、属性注入
如MainActivity类,标注在属性上。注意,被标注的属性不能使用private修饰,否则无法注入。
public class MainActivity extends Activity {
@Inject
Car car;
}
3、方法注入
标注在public方法上,Dagger2会在构造器执行之后立即调用这个方法。
方法注入和属性注入基本上没有区别, 那么什么时候应该使用方法注入呢?
比如该依赖需要this对象的时候,使用方法注入可以提供安全的this对象,因为方法注入是在构造器之后执行的。
public class MainActivity extends Activity {
private Car car;
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerMainActivityComponent.create().inject(this);
}
@Inject
public void setCar(Car car) {
this.car = car;
}
}
@Module和@Provides
使用@Inject标记构造器提供依赖是有局限性的,比如需要注入的对象是第三方库提供的,我们无法在第三方库的构造器上加上@Inject注解。
或者,我们使用依赖倒置的时候,因为需要注入的对象是抽象的,@Inject也无法使用,因为抽象的类并不能实例化,比如:
public interface Vehicle {
void drive();
}
public class Car implements Vehicle {
@Inject
public Car() {}
public void drive() {
Log.d("dagger", "drive car!");
}
}
public class Driver {
private Vehicle mVehicle;
@Inject
public Driver(Vehicle vehicle) {
mVehicle = vehicle;
}
public void drive() {
mVehicle.drive();
}
}
编译的时候会报错,Vehicle是接口类,不能实现对象实例化,这时候,就需要用到@Module和@Provides来提供依赖了。
@Module
public class VehicleModule {
@Provides
public Vehicle provideCar() {
return new Car();
}
}
@Component(modules = VehicleModule.class)
public interface MainActivityComponent {
void inject(MainActivity activity);
}
@Module需要和@Provide一起使用才具有作用,并且@Component也需要指定Module。
@Module是告诉Component,可以从这里获取依赖对象。Component就会去找被@Provides标注的方法,相当于构造器的@Inject,可以提供依赖。
依赖多个modules:
@Module
public class DriverModule {
@Provides
public Driver providerDriver(Vehicle vehicle) {
return new Driver(vehicle);
}
}
@Module
public class VehicleModule {
@Provides
public Vehicle provideCar() {
return new Car();
}
}
@Component(modules = {VehicleModule.class, DriverModule.class})
public interface MainActivityComponent {
void inject(MainActivity activity);
}
@Named和@Qualifier
当我有两个相同的依赖(都继承某一个父类或者都实现某一个接口)可以提供给高层时,那么程序就不知道我们到底要提供哪一个依赖,因为它找到了两个。
这时候我们就可以通过限定符为两个依赖分别打上标记,指定提供某个依赖。
@Module
public class VehicleModule {
@Named("car")
@Provides
public Vehicle provideCar() {
return new Car();
}
@Named("truck")
@Provides
public Vehicle provideTruck() {
return new Truck();
}
}
public class Driver {
private Vehicle mVehicle;
@Inject
public Driver(@Named("car") Vehicle vehicle) {
mVehicle = vehicle;
}
public void drive() {
mVehicle.drive();
}
}
@Qualifier的作用和@Named是完全一样的,不过更推荐使用@Qualifier,因为@Named需要手写字符串,容易出错。
@Qualifier不是直接注解在属性上的,而是用来自定义注解的。
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface CarVehicle {
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface TruckVehicle {
}
@Module
public class VehicleModule {
@CarVehicle
@Provides
public Vehicle provideCar() {
return new Car();
}
@TruckVehicle
@Provides
public Vehicle provideTruck() {
return new Truck();
}
}
public class Driver {
private Vehicle mVehicle;
public Driver(@CarVehicle Vehicle vehicle) {
mVehicle = vehicle;
}
public void drive() {
mVehicle.drive();
}
}
@Component
可以理解为注入器,在需要注入依赖的目标类中使用Component完成注入。一个Component可以依赖一个或多个Component,并拿到被依赖Component暴露出来的实例。
Component中一般使用两种方式定义方法:
-
void inject(目标类 obj):Dagger2会从目标类开始查找@Inject注解,自动生成依赖注入的代码,调用inject可完成依赖的注入。
-
Object getObj()
Dagger2会到Driver类中找被@Inject注解标注的构造器,自动生成提供Driver依赖的代码,这种方式一般为其他Component提供依赖。
被依赖的Component必须暴露需要提供依赖的接口,否则依赖的Component无法完成注入。
public class MainActivity extends Activity {
@Inject
Driver driver;
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 这个类是重新编译后Dagger2自动生成的,所以写这行代码之前要先编译一次
DaggerMainActivityComponent.create().inject(this);
}
}
@Scope和@Singleton
@Scope不能直接拿来使用,用于定义注解,@Singleton是它的默认实现。
用@Scope自定义一个注解@ActivityScope,注解名字要见名知意:
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ActivityScope {}
这里先看下默认注解@Singleton,看看它的用法
@Module
public class DriverModule {
@Singleton
@Provides
public Driver providerDriver(@TruckVehicle Vehicle vehicle) {
return new Driver(vehicle);
}
}
@Singleton
@Component(modules = {DriverModule.class, VehicleModule.class})
public interface DriverComponent {
Driver getDriver();
@CarVehicle
Vehicle getVehicle();
}
@ActivityScope // 这里使用@Singleton,或者没有@Scope注解都会报错,需要自定义一个非@Singleton注解
@Component(dependencies = DriverComponent.class)
public interface MainActivityComponent {
void inject(MainActivity activity);
}
这么实现,注入的多个Pot对象,公用一个实例,但是是有前提的,必须要在PotComponent对象实例相同的情况。
如果新建了一个PotComponent对象,通过该Component注入的对象,必然是不一样的。这里的单例可以理解为"局部单例",是在Component对象发生没有变化的前提下的单例。
那么,怎么来实现"全局单例"呢?这就需要利用Component对象不发生改变这条规则,保证Component对象全局不变,那就保证了用该Component对象注入的对象唯一性。
比如,我们可以在Application实例化一个Component,在多个需要用到的地方,使用这里定义的同一个Component。
public class App extends Application {
private PotComponent potComponent;
@Override
public void onCreate() {
super.onCreate();
potComponent = DaggerPotComponent.builder()
.flowerComponent(DaggerFlowerComponent.create())
.build();
}
public PotComponent getPotComponent() {
return potComponent;
}
}
@Subcomponent
@Subcomponent提供了另外一种联系Component的方式,可以理解为子组件,有点像继承关系,但是写法又不像,挺费解的。
类比类继承关系,子类继承父类,子类包含父类的特性;但是这里,被@Subcomponent标记的Component,像是一个零部件,作为部分功能存在,父Component却起主导作用。
看代码吧:
@Module
public class AppModule {
@Provides
public Engine provideEngine() {
return new Engine();
}
}
@Component(modules = AppModule.class)
public interface AppComponent {
//需要将SubComponent追加到被依赖的Component中
PresenterComponent addSub(PresenterModule PresenterModule);
}
@Module
public class PresenterModule {
@Provides
public Car provideCar(Engine engine) {
// Car 依赖 Engine
return new Car(engine);
}
}
@Subcomponent(modules = PresenterModule.class)
public interface PresenterComponent {
void inject(MainActivity activity);
}
public class MainActivity extends Activity {
@Inject
Car car;
@Inject
Engine engine;
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppModule AppModule = new AppModule();
AppComponent AppComponent = DaggerAppComponent.builder()
.AppModule(AppModule)
.build();
PreseterModule PreseterModule = new PreseterModule();
PresenterComponent PresenterComponent = DaggerPresenterComponent.builder()
.AppComponent(AppComponent)
.PreseterModule(PreseterModule)
.inject(this);
}
}
注意点:
1、dependencies实现的Component间的依赖关系,被依赖的Component需要暴露提供依赖的方法,否则无法注入依赖;而@SubComponent的实现,不需要在被依赖的Component暴露方法,可以完全继承Component中的全部依赖。
2、在Component间需要保持独立性的时候建议使用dependencies;而在Component间关系紧密,或者说需要组合功能时,建议使用@SubComponent
Lazy
Dagger2还支持Lazy模式,通过Lazy模拟提供的实例,在@Inject的时候并不初始化,而是等到你要使用的时候,主动调用其.get方法来获取实例。
public class MainActivity extends Activity {
@Inject
Lazy<Driver> driverLazy;
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DaggerMainActivityComponent.builder()
.potComponent(((App) getApplication()).getDriverComponent())
.build().inject(this);
Driver driver = driverLazy.get();
}
}
参考资料
Dagger2 最清晰的使用教程
dagger2系列之依赖方式dependencies、包含方式(从属方式)SubComponent