警告!這不是一個乾貨的文章!java
我的認爲,學技術不宜太浮躁。對於一項技術一味地追求乾貨其實並不必定有用,貨太乾容易噎着,哈哈~不如按部就班慢下來,一點點去體會技術的來龍去脈。(這個系列適合於:瞭解但沒有在項目裏大規模應用Dagger2的讀者)app
出來混早晚要還的,技術債Dagger2:Android篇(上)ide
出來混早晚要還的,技術債Dagger2:Android篇(中)@Scope、@Singletonpost
本覺得閱讀一些文檔,寫一些Demo就能駕馭工做中的項目...我錯了,我不再會有這麼愚蠢的想法了... 這麼多依賴關係,誰扛得住啊!因此仍是一點點來吧。學習
前倆篇文章事後,我猜你們對下面的代碼已經很熟悉了:ui
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
void inject(MainActivity mainActivity);
SharedPreferences getSharedPrefs();
}
@Module
public class AppModule {
Application application;
public AppModule(Application application) {
this.application = application;
}
@Provides
Application providesApplication() {
return application;
}
@Provides
@Singleton
public SharedPreferences providePreferences() {
return application.getSharedPreferences(DATA_STORE,Context.MODE_PRIVATE);
}
}
DaggerAppComponent appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
複製代碼
很基本,很簡單的Dagger應用。不過你們有沒有感受到這個appModule(new AppModule(this))
特別煩?安利我用的時候,說依賴注入,看不見new。我哼哧哼哧寫這麼多,這不仍是new出來的?this
那麼問題來了,是否是能夠不須要appModule(new AppModule(this))
呢?固然能夠。用過Dagger-Android
的朋友,確定很清楚,的確看不到任何new。那麼這篇文章,我們就來看看如何完全不用new。spa
固然這也是Dagger-Android的原理code
作這一切的前提是這個註解。這個註解是幹啥的呢?說白了,給Component提供Module的依賴。
我們先來想一個問題,下面代碼存在的意義:
DaggerAppComponent appComponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
複製代碼
Dagger爲咱們所需的依賴生成實例,那麼必然須要構建整個依賴關係網。Dagger就算是再神奇,也不可能憑空把整個咱們所須要依賴關係構建出來,因此須要咱們適時的「提供和引導」。那麼new AppModule(this)
就是給Dagger進行提供,由於從咱們上述的代碼中,Dagger是不知道該怎麼去實例化這個AppModule
,所以須要咱們對其進行提供。
那麼話又說回來,咱們在上述的代碼中,告訴它如何去實例化AppModule
,不就能夠避免咱們手動去new AppModule(this)
了麼?
沒錯,@Component.Builder
就是作這個的。
累死了,繞了一圈不知道你們理沒理解@Component.Builder存在的含義了。
對於咱們的AppModule
來講,實例化它的關鍵是如何提供一個Application
。
public AppModule(Application application) {
this.application = application;
}
複製代碼
對於Dagger也是如此,它不能實例化AppModule
的緣由是它不知道或者說沒辦法去獲取一個Application
實例。所以,對於Dagger來講,咱們應該給它提供Application
的實例,而非AppModule
。
改造須要一步步來:第一步,咱們使用@Component.Builder
去改造AppComponent
:
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
void inject(MainActivity mainActivity);
SharedPreferences getSharedPrefs();
// 改造內容
@Component.Builder
interface Builder {
AppComponent build();
// 此時還未改造這行代碼
Builder appModule(AppModule appModule);
}
}
複製代碼
如今咱們告訴了Dagger,你要以
@Component.Builder
註解的接口那樣去實例化咱們所需的AppComponent
。
是否是發現這裏添加的方法和DaggerAppComponent
生成的代碼很像?沒錯Dagger默認實例化AppComponent
就是以這種代碼進行的。
不過,對於咱們這個AppModule
來講,咱們不須要關係它是怎麼初始化(由於咱們只須要它所提供給咱們的依賴)。對於Dagger來講也是如此: Dagger想要爲咱們提供被@Provides
標註的依賴,只須要擁有Application
實例便可。由於只要擁有Application
實例Dagger就有辦法實例化AppModule
,直接new便可。
因此這裏咱們須要一種方式來告訴Dagger:我要提供給你,在@Module
中須要的內容。對於我們的這個demo來講,我們須要用一種方式把Dagger所須要的Application
給他。
而作到這一點的就是@BindsInstance
。
按照官網的介紹,此註解用於標識Component Builder/SubComponent Builder中的某個方法,該方法容許將實例綁定到Component中。
因此對於咱們的AppModule
來講,它只須要提供@Provides
的內容就能夠了!,它所須要的,Dagger會按照咱們的「指示」,注入進來。也就是這個樣子:
@Module
public class AppModule {
@Provides
@Singleton
// 外部傳入Application實例(Dagger會按照咱們的「指示」,注入進來)
public SharedPreferences providePreferences(Application application) {
return application.getSharedPreferences("store", Context.MODE_PRIVATE);
}
}
複製代碼
而咱們的AppConponent
這樣就能夠了:
@Singleton
@Component(modules = {AppModule.class})
public interface AppComponent {
void inject(MainActivity mainActivity);
SharedPreferences getSharedPrefs();
@Component.Builder
interface Builder {
AppComponent build();
@BindsInstance
// 此時的application就會被,注入到AppModule的providePreferences方法中
Builder application(Application application);
}
}
複製代碼
build事後,咱們初始化DaggerAppComponent
,只需如此寫:
DaggerAppComponent appComponent = DaggerAppComponent.builder()
.application(this)
.build();
複製代碼
那麼Dagger是如何爲咱們生成DaggerAppComponent
的呢?
public final class DaggerAppComponent implements AppComponent {
private Provider<Application> applicationProvider;
private Provider<SharedPreferences> providePreferencesProvider;
private DaggerAppComponent(Builder builder) {
initialize(builder);
}
public static AppComponent.Builder builder() {
return new Builder();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.applicationProvider = InstanceFactory.create(builder.application);
this.providePreferencesProvider =
DoubleCheck.provider(
AppModule_ProvidePreferencesFactory.create(builder.appModule, applicationProvider));
}
@Override
public void inject(MainActivity mainActivity) {}
@Override
public SharedPreferences getSharedPrefs() {
return providePreferencesProvider.get();
}
private static final class Builder implements AppComponent.Builder {
private AppModule appModule;
private Application application;
@Override
public AppComponent build() {
if (appModule == null) {
this.appModule = new AppModule();
}
if (application == null) {
throw new IllegalStateException(Application.class.getCanonicalName() + " must be set");
}
return new DaggerAppComponent(this);
}
@Override
public Builder application(Application application) {
this.application = Preconditions.checkNotNull(application);
return this;
}
}
}
複製代碼
對於AppModule
來講,只是簡單的new出來,當咱們須要@Provides
時,只是將所需的application
傳進去。而咱們的application
以成員變量的身份呆在了DaggerAppComponent
「體內」。
這篇內容,其實並非爲了去講@Component.Builder
和@BindsInstance
。而是儘量的經過它們,來加深你們去Component和Module的理解。去感覺Dagger的實現,更好的去理解依賴注入。對與咱們而言,須要用其形,學其神。
這樣咱們纔不會受制於框架,而是駕馭框架。