Dagger2是Google在Square開源的Dagger的基礎(chǔ)上將反射注入的方式修改到編譯時而得到的依賴注入框架没讲。
官方地址:GitHub
官方文檔:https://google.github.io/dagger/
四個關(guān)鍵注解:
@Inject
用于類構(gòu)造器和類的屬性灭忠。
- 用在類的構(gòu)造器上用來注解提供對象的方法,Dagger會根據(jù)該構(gòu)造器來生成該類的工廠類
ClassName_Factory
。工廠類實(shí)現(xiàn)了Factory<T>
接口栈妆,通過覆寫的get()
方法調(diào)用注解的構(gòu)造方法提供類的對象:
public final class Noodle_Factory implements Factory<Noodle> {
private static final Noodle_Factory INSTANCE = new Noodle_Factory();
@Override
public Noodle get() {
return new Noodle();
}
public static Factory<Noodle> create() {
return INSTANCE;
}
/** Proxies {@link Noodle#Noodle()}. */
public static Noodle newNoodle() {
return new Noodle();
}
}
原始類:
class Noodle {
@Inject
public Noodle() {
}
@Override
public String toString() {
return "面條";
}
}
- 用在類的屬性上用來注解該屬性需要依賴注入。Dagger會為根據(jù)該類需要注入的屬性生成
ClassName_MembersInjector
注入類厢钧,該類實(shí)現(xiàn)了MembersInjector<T>
接口鳞尔。通過靜態(tài)的create(arg...)
方法來生成實(shí)例,該方法的參數(shù)類型為需要注入的屬性對應(yīng)的Provider<T>
類型(Factory<T>
是Provider<T>
的子類型)早直,參數(shù)個數(shù)與需要注入的字段個數(shù)一致寥假。注入類通過覆寫的injectMembers(T instance)
方法來注入目標(biāo)類需要的屬性:
public final class ZhaiNan_MembersInjector implements MembersInjector<ZhaiNan> {
private final Provider<Baozi> baoziProvider;
private final Provider<Noodle> noodleProvider;
public ZhaiNan_MembersInjector(Provider<Baozi> baoziProvider, Provider<Noodle> noodleProvider) {
assert baoziProvider != null;
this.baoziProvider = baoziProvider;
assert noodleProvider != null;
this.noodleProvider = noodleProvider;
}
public static MembersInjector<ZhaiNan> create(
Provider<Baozi> baoziProvider, Provider<Noodle> noodleProvider) {
return new ZhaiNan_MembersInjector(baoziProvider, noodleProvider);
}
@Override
public void injectMembers(ZhaiNan instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.baozi = baoziProvider.get();
instance.noodle = noodleProvider.get();
}
public static void injectBaozi(ZhaiNan instance, Provider<Baozi> baoziProvider) {
instance.baozi = baoziProvider.get();
}
public static void injectNoodle(ZhaiNan instance, Provider<Noodle> noodleProvider) {
instance.noodle = noodleProvider.get();
}
}
若一個類自身需要為別的類提供依賴(他的構(gòu)造器用@Inject注解),同時也需要別的類提供依賴(他的屬性用@Inject注解)霞扬,他對應(yīng)的工廠類會依賴于他對應(yīng)的MembersInjector
糕韧,并調(diào)用MembersInjectors.injectMembers()
來為自身注入依賴:
public final class ZhaiNan_Factory implements Factory<ZhaiNan> {
private final MembersInjector<ZhaiNan> zhaiNanMembersInjector;
public ZhaiNan_Factory(MembersInjector<ZhaiNan> zhaiNanMembersInjector) {
assert zhaiNanMembersInjector != null;
this.zhaiNanMembersInjector = zhaiNanMembersInjector;
}
@Override
public ZhaiNan get() {
return MembersInjectors.injectMembers(zhaiNanMembersInjector, new ZhaiNan());
}
public static Factory<ZhaiNan> create(MembersInjector<ZhaiNan> zhaiNanMembersInjector) {
return new ZhaiNan_Factory(zhaiNanMembersInjector);
}
}
原始類:
public class ZhaiNan {
@Inject
Baozi baozi;
@Inject
Noodle noodle;
@Inject
public ZhaiNan() {
}
public String eat() {
StringBuilder sb = new StringBuilder();
sb.append("我吃的是 ");
if (baozi != null) {
sb.append(baozi.toString());
}
if (noodle != null) {
sb.append(" ");
sb.append(noodle.toString());
}
return sb.toString();
}
}
class Noodle {
@Inject
public Noodle() {
}
@Override
public String toString() {
return "面條";
}
}
@Module 和 @Provides
上面介紹了Dagger生成的核心類,即為被注入的屬性生成的工廠類以及注入類喻圃,工廠類用來提供該屬性需要的對象萤彩,注入類提供將該對象綁定要屬性需要的方法。生成工廠類需要使用@Inject
注解提供依賴的類的構(gòu)造函數(shù)斧拍,但現(xiàn)實(shí)情況是雀扶,我們很多時候沒法修改該類,這個時候我們就需要手動實(shí)現(xiàn)提供該該類的對象的方法饮焦。使用@Module
和 @Provides
來解決這個問題怕吴。@Module
用來注解我們自己實(shí)現(xiàn)的工廠類窍侧,@Provides
用來注解里面的工廠方法县踢,Dagger會為每一個工廠方法生成一個工廠類。假如@Module
標(biāo)注的類名為ZhaiNanModule
伟件,@Provides
標(biāo)注的方法名為provideBaozi()
硼啤,生成的工廠類則為:
public final class ZhaiNanModule_ProvideBaoziFactory implements Factory<Baozi> {
private final ZhaiNanModule module;
public ZhaiNanModule_ProvideBaoziFactory(ZhaiNanModule module) {
assert module != null;
this.module = module;
}
@Override
public Baozi get() {
return Preconditions.checkNotNull(
module.provideBaozi(), "Cannot return null from a non-@Nullable @Provides method");
}
public static Factory<Baozi> create(ZhaiNanModule module) {
return new ZhaiNanModule_ProvideBaoziFactory(module);
}
}
Module 類:
@Module
public class ZhaiNanModule {
@Provides
public ZhaiNan provideZaiNan() {
return new ZhaiNan();
}
@Provides
public Noodle provideNoodle() {
return new Noodle();
}
@Provides
public Baozi provideBaozi() {
return new Baozi();
}
}
注意:
- 在
@Provides
標(biāo)注的方法中直接new 出來的對象,即使該對象內(nèi)部有需要被注入的屬性斧账,Dagger也沒法自動去完成依賴注入谴返。即Dagger不會為new出來的對象自動注入依賴。- 若提供依賴的類的構(gòu)造方法使用了
@Inject
注解咧织,并且@Module
注解的類也中提供了返回該類的方法嗓袱,Dagger會優(yōu)先使用@Module
注解的類中的方法。
@Component()
依賴提供方和依賴需求方的紐帶习绢。@Component()
注解的接口或抽象類中定義提供已經(jīng)注入好依賴的對象的方法(前提是Module中或Dagger生成的代碼中提供該對象的方法會注入該對象的依賴)或者為對象注入依賴方法渠抹。被它注解的接口中定義的方法若為返回一個對象蝙昙,則該方法執(zhí)行完后返回對象中定義的所有需要被注入的依賴都會被注入好,若該方法接受一個對象作為參數(shù)梧却,則該方法執(zhí)行完后該對象內(nèi)需要被注入的屬性都會被注入好奇颠。
若接口名稱為ZhaiNanComponent
,則Dagger生成的類名為DaggerZhaiNanComponent
放航,并且實(shí)現(xiàn)了接口中定義的方法:
原始類:
@Component(modules = {ZhaiNanModule.class}) // 指定提供依賴方法的模塊
public interface ZhaiNanComponent {
ZhaiNan get();
void inject(MainActivity mainActivity);
void inject(ZhaiNan zhaiNan);
}
生成的類:
public final class DaggerZhaiNanComponent implements ZhaiNanComponent {
private Provider<ZhaiNan> provideZaiNanProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private Provider<Baozi> provideBaoziProvider;
private Provider<Noodle> provideNoodleProvider;
private MembersInjector<ZhaiNan> zhaiNanMembersInjector;
private DaggerZhaiNanComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static ZhaiNanComponent create() {
return new Builder().build();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.provideZaiNanProvider = ZhaiNanModule_ProvideZaiNanFactory.create(builder.zhaiNanModule);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create(provideZaiNanProvider);
this.provideBaoziProvider = ZhaiNanModule_ProvideBaoziFactory.create(builder.zhaiNanModule);
this.provideNoodleProvider = ZhaiNanModule_ProvideNoodleFactory.create(builder.zhaiNanModule);
this.zhaiNanMembersInjector =
ZhaiNan_MembersInjector.create(provideBaoziProvider, provideNoodleProvider);
}
@Override
public ZhaiNan get() {
return provideZaiNanProvider.get();
}
@Override
public void inject(MainActivity mainActivity) {
mainActivityMembersInjector.injectMembers(mainActivity);
}
@Override
public void inject(ZhaiNan zhaiNan) {
zhaiNanMembersInjector.injectMembers(zhaiNan);
}
public static final class Builder {
private ZhaiNanModule zhaiNanModule;
private Builder() {}
public ZhaiNanComponent build() {
if (zhaiNanModule == null) {
this.zhaiNanModule = new ZhaiNanModule();
}
return new DaggerZhaiNanComponent(this);
}
public Builder zhaiNanModule(ZhaiNanModule zhaiNanModule) {
this.zhaiNanModule = Preconditions.checkNotNull(zhaiNanModule);
return this;
}
}
}
現(xiàn)在我們可以這么使用該類:
@Inject
ZhaiNan zhaiNan;
// 為對象注入依賴
ZhaiNanComponent zhaiNanComponent = DaggerZhaiNanComponent.builder()
.zhaiNanModule(new ZhaiNanModule())
.build();
zhaiNanComponent.inject(this); // 執(zhí)行后zhaiNan就會被賦值
zhaiNanComponent.inject(zhaiNan); // 要執(zhí)行這一步烈拒,因?yàn)閦haiNan在Module里是new出來的
// 獲取一個依賴被注入完畢的對象
zhaiNan = DaggerZhaiNanComponent.builder().build().get();
注意:若Module中提供依賴的方法為static,則可以用
ZhaiNanComponent zhaiNanComponent = DaggerZhaiNanComponent.create();
來創(chuàng)建Component
輔助性注解
@Singleton 和 @Scope
@Singleton
是@Scope
被注解的一個注解广鳍,用來和@Provides
注解一起注解提供依賴的方法荆几,被@Singleton
注解的方法能在@Component
范圍內(nèi)提供單例(該Component同時也需要被@Singleton
注解)。我們可以直接使用@Singleton
搜锰,也可以像這樣自定義一個局部單例注解:
@Scope
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface ActivityScoped {
}
其中@Scope
是必須的伴郁,其他可選。現(xiàn)在我們可以使用@ActivityScoped
去注解@Provides
方法和@Component
類蛋叼,來指定在該@Component
中@Provides
方法返回同一個對象實(shí)例焊傅。使用@ActivityScoped
注解上面的provideBaozi()
方法后,生成的DaggerZhaiNanComponent
類的private void initialize(final Builder builder)
方法中生成provideBaoziProvider
方式變成了:
// 原來是
//this.provideBaoziProvider = ZhaiNanModule_ProvideBaoziFactory.create();
this.provideBaoziProvider = DoubleCheck.provider(ZhaiNanModule_ProvideBaoziFactory.create());
使用了DoubleCheck<T>
類來生成了一個代理狈涮,通過DoubleCheck
類覆寫的get()
方法來提供單例狐胎,所以它能實(shí)現(xiàn)Component級別的單例。
@Named 和 @Qualifiers
當(dāng)你需要在Module中定義多個返回同類型的方法的時候歌馍,@name
就派上用場了握巢。@name
是@Qualifiers
注解的一個注解,用來注解@Provides
注解的提供依賴對象的方法松却,和@Inject
注解的需要被注入的對象暴浦,以區(qū)分使用哪個方法來提供實(shí)例:
@Module
public class ZhaiNanModule {
@Provides
@Named("baozi1")
public static Baozi provideBaozi1() {
return new Baozi();
}
@Provides
@Named("baozi2")
public static Baozi provideBaozi2() {
return new Baozi();
}
}
public class MainActivity extends AppCompatActivity {
@Inject
ZhaiNan zhaiNan;
@Inject
@Named("baozi1")
Baozi baozi;
@Inject
@Named("baozi2")
Baozi baozi2;
}
生成的DaggerZhaiNanComponent
類的private void initialize(final Builder builder)
方法中生成mainActivityMembersInjector
方式變成了:
this.mainActivityMembersInjector =
MainActivity_MembersInjector.create(
ZhaiNanModule_ProvideZaiNanFactory.create(),
ZhaiNanModule_ProvideBaozi1Factory.create(),
ZhaiNanModule_ProvideBaozi2Factory.create());
若不想寫每次寫個name,可以自定義一個注解:
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface Baozi1 {
}
延遲加載和強(qiáng)制重新加載
分別使用Lazy<T>
和Provider<T>
類來實(shí)現(xiàn):
public class Test {
@Inject
@Named("Test")
Lazy<String> name;
@Inject
Provider<Integer> randomValue;
public String getName() {
return name.get();
}
public int getRandomValue() {
return randomValue.get().intValue();
}
}
這樣當(dāng)?shù)谝淮握{(diào)用getName()
時晓锻,我們需要的String
對象才被創(chuàng)建歌焦;而每次調(diào)用getRandomValue()
時,一個新的Integer對象都會被創(chuàng)建砚哆。
Component依賴
若一個Component需要依賴另一個独撇,可以通過指定@Component(modules = XModule.class, dependencies = OtherComponent.class)
,這樣就可以使用OtherComponent定義的方法躁锁。在創(chuàng)建Component的時候把依賴的Component傳入:
XiaoChiComponent xiaoChiComponent = DaggerXiaoChiComponent.builder()
.build();
DaggerFoodComponent.builder()
.xiaoChiComponent(xiaoChiComponent)
.build()
.inject(this);
SubComponent
Component依賴類似于組合纷铣,而SubComponent類似于繼承:
@Subcomponent(modules = FoodModule.class)
public interface SubComponent {
void inject(ThirdActivity activity);
}
@Component(modules = XiaoChiModule.class)
public interface ParentComponent {
SubComponent provideSubComponent();
}
DaggerParentComponent.builder().build()
.provideSubComponent().inject(this);