1、前言
依賴注入定義
目標類中所依賴的其餘的類的初始化過程,不是經過手動編碼的方式建立的。
是將其餘的類已經初始化好的實例自動注入的目標類中。
「依賴注入」也是面向對象編程的 設計模式 ————-組合的配套使用
做用 :下降程序的耦合,耦合就是由於類之間的依賴關係所引發的
產生場景:在一個對象裏去建立另外一個對象的實例
問題:過多的類,對象之間的依賴會形成代碼難以維護。
不符合開閉原則的對象的引用寫法:錯誤示例:
public class ClassA {
classB b ;
public ClassA (ClassB b ){
this.b = b;
}
}
經過依賴注入的方式 ,將ClassB對象注入到ClassA中。從而靈活配置ClassA 的屬性
public class ClassA{
@Inject
ClassB b;
public ClassA(){...}
}
常見的四種注入方式
一、接口注入
定義ClassBInterface接口,在其內定義setB()函數.ClassAInterface去實現ClassBInterface 接口,在ClassAInterface類中定義了一個ClassBInterface成員變量,並複寫setB()函數,最終經過setB()函數完成接口注入操做。
public interface ClassBInterface {
void setB(ClassB b);
}
public class ClassA implements ClassBInterface {
ClassB classB;
@Override
public void setB(ClassB b) {
classB = b;
}
}
二、set注入——依賴注入的(核心:外部傳遞而來)重要方法之一
public class ClassAset {
ClassB classb;//定義成員變量
//經過set方法完成注入(對其成員變量的賦值),更加剝離了各個部分的耦合性
public void setCalssB(ClassB b){
classb =b;
}
}
ps:不少時候都是經過
三、經過構造方法注入-經常使用
public class ClassAConstructor {
//在classA中定義一個ClassB 成員變量
ClassB classB;
//將ClassB做爲參數,傳遞至ClassA的構造函數中,進行成員變量ClassB的賦值
public ClassAConstructor(ClassB b){
classB = b;
}
}
四、經過Java依賴註解完成方法注入-重點
/**
* 對象的組合-在一個類中引用其餘對象,容器依賴持有的類的實現
* */
public class FruitContainer {
//在FruitContainer類中持有了Banana的引用,從而調用引用類的方法完成某些功能
Banana banana;
//在FruitContainer的構造方法中經過banana構造方法新建了一個banana對象
public FruitContainer(){
banana =new Banana();
}
}
涉及場景:業務需求改變,被持有的類的構造方法進行了改變,那麼持有這個類的不少類都有可能須要進行不一樣長度的改變,形成了代碼的很大的耦合性增長,下降了擴展性,是種比較嚴重的不符合開閉原則的寫法
思考:
在FruitContainer依賴Banana的實現的狀況下,用什麼辦法在不修改FruitContainer的類狀況下,知足Banana或是其內在的構造函數進行了修改。
答: 經過註解的方式 ,注入到宿主類:FruitContainer 類中
public class FruitConainerInject{//類不用關心具體(水果)引用類的實現
添加@Inject,自動完成注入功能————> 這時候並不會完成注入,須要引入註解庫並在目標類中調用才完成注入
Fruit f;
public FruitContainerInject(){
//動態注入
}
}
小結:
不要在須要依賴的類中經過new 類建立依賴而是經過方法提供的參數注入進來
2、dagger2的使用流程
一、將須要注入的對象的類的構造參數使用@Inject標註,在編譯的時候編譯器會通知dagger2 實例化該類
二、新建component接口,並在開始使用@Component註解進行註釋,自定義void inject()函數,並傳入須要依賴注入的對象的類型
三、使用編譯器的make project 功能 ,進行編譯,在build文件夾內目錄下生成Component所對應的類,生成的類的名字格式爲「Dagger+自定義的Component名字」
四、在須要注入的目標類(通常是Activity or Fragment之類)中,使用@Inject標註要注入的變量,在初始化時候調用自動生成的Component類的builder().xxModule(xxx).build().自定義inject()方法,完成構建
3、dagger2的基本用法
0、導入
compileOnly 'org.glassfish:javax.annotation:10.0-b28'
annotationProcessor 'com.google.dagger:dagger-compiler:2.5'
implementation 'com.google.dagger:dagger:2.5’
導入可能存在的問題:
Error:Could not get unknown property 'classpath' for task ':app:transformJackWithJackForDebug' of type com.android.build…..
- 1. 刪除project根目錄build.gradle中的: classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8’ (通常如今都沒有)
-
2.app的build.gradle中,刪除apply plugin 'android-apt'
-
3.在app的build.gradle中,dependencies中的 apt 'com.google.dagger:dagger-compiler:2.1.0' 改成
- annotationProcessor 'com.google.dagger:dagger-compiler:2.1.0'
一、@Inject 註解
一、標記在須要依賴的變量,dagger2爲其提供依賴,並實例化有此註解的類
二、使用在構造函數上,構造函數工廠,經過標記構造函數讓dagger2 使用,從而提供相關的依賴
ps:dagger2 經過@Inject標記能夠在須要這個類實例的時候,來找到這個構造方法,將相關的實例new出來
(1)、@Inject標記的變量
經過@Inject 標記的變量 ,在make project後會在其build下的source文件夾內的debug,包名下生成:
"類名_MembersInjector」文件
@Override
public void injectMembers(Car instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
//經過調用typeProvider.get()函數獲取到.type ,在這裏type 是經過inject標註的
instance.tyre = tyreProvider.get();
}
ps:經過@Inject 標記的成員變量不能被命名爲private 屬性,不然沒法獲取到
(2)、@Inject標記的構造方法
經過@Inject 標記的構造方法 ,在make project後會在其build下的source文件夾內的debug,包名下生成:
"類名_Factory」文件
INSTANCE;
@Override
public Tyre get() {
return new Tyre();
}
public static Factory<Tyre> create() {
return INSTANCE;
}
依賴注入是依賴的對象實例————>須要注入的實例屬性
新建工廠實例並調用成員屬性注入類完成Tyre的實例注入
二、@Component 註解——注入者與被注入者之間的牆梁,more Improtant
用於標註接口 或是 抽象類,能夠完成依賴注入的過程。
將@Inject 和@Module 聯繫起來的牆梁,從@Module中獲取依賴並將依賴注入給 @Inject
@Component標記的接口或是抽象類,在make project後會在其build下的source文件夾內的debug,包名下生成:
"Dagger接口名稱」文件
@Component
public interfaceCarComponent {
/**一、參數必須是須要注入依賴的類型,不能是其父類 or 子類
*二、注入接口的方法的返回值 必須是void,命名能夠任意可是最好是inject+須要注入依賴的類名,便於識別
**/
voidinjectCar(Car car); <——————將依賴注入到的目標位置
}
private MembersInjector<Car> carMembersInjector;
private void initialize(final Builder builder) {
//經過carMembersInjector查找目標類對應的成員屬性注入類,將依賴的屬性的工廠實例傳入給注入類,完成依賴注入
this.carMembersInjector = Car_MembersInjector.create(Tyre_Factory.create());
}
public Car() {
//經過Component如下方法注入car 屬性,整個流程
DaggerCarComponent.builder().build().injectCar(this);
}
標記了@Inject 的變量,須要配套對其對象的構造方法 進行@Inject的構造方法標記 來肯定用何種構造方法完成對象的構建,才能建立完成。最後在構建好的使用了@Component修飾的接口中,在目標類的構造方法中使用Component的builder()方法調用接口中的方法完成整個方法的構建
4、dagger2的源碼
DaggerCarComponent.builder().build().injectCar(this); 經過構建者模式完成建立
在build() 方法中完成了DaggerCarComponent 對象的建立:
public CarComponent build() {
return new DaggerCarComponent(this);
}
private void initialize(final Builder builder) {
//調用成員注入器Car_MembersInjector 經過create方法完成carMembersInjector對象的構建
this.carMembersInjector = Car_MembersInjector.create(Tyre_Factory.create());
}
injectCar():完成實際的成員變量的注入
@Override
public void injectCar(Car car) {
carMembersInjector.injectMembers(car);
}
injectMembers():在 xx_Factory下完成對象的建立
@Override
public void injectMembers(Car instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
//最後經過tyreProvider.get()函數完成注入
instance.tyre = tyreProvider.get();
}
5、dagger2的經常使用註解-區別於@Inject
思考:如何須要提供的類構造函數沒法修改怎麼辦?好比引用庫 裏面的類 沒法修改如何解決?
@Module 註解
- 能夠給不能修改的類提供依賴,dagger2 會在該類中尋找實例化某個類所須要的依賴
- 但須要配合@Provide 註解一塊兒使用
@Provides
- 標註一個Module中的方法,可使須要提供依賴的時候被調用。
- 同時,被@Provides註解修飾的方法他的返回值就是依賴對象的實例。
ps:@Provides註解只能使用在Module當中
一、建立一個用@Module修飾的目標類,和一個@Provides修飾的構建類
@Module
public class CarModule {
//在須要提供依賴的時候被調用
@Provides
static Car provideCar(){
return new Car();
}
}
二、在component 橋樑類裏指明modules對應的類字節碼對象,是具體哪一個module
@Component(modules = CarModule.class)
public interface CarComponent {
void injectCar(Car car);
}
三、make program 後生成 :「CarModule_ProvideCarFactory」
在其內部調用了Module的內部方法函數 建立car對象
@Override
public Car get() {
return Preconditions.checkNotNull(
CarModule.provideCar(), "Cannot return null from a non-@Nullable @Provides method");
}
通常依賴注入的初始化使用方法:
xxxComponent
.builder()
.xxxModule(new xxxModule(
view:this, new xxx實現InteractorImpl()
) )
.build()
.inject(activity:this);
ps:
- InteractorImpl()是P層 被@Inject的標註方法;
- 同時 P層的對象 也是被@Inject 標記註解
- 將Module層 標記爲@Module註解
- 根據須要標註 M層內的方法 @Provieds
- 添加@Component(modules = xx.class)註解,並在其內定義一個inject(傳入xxActivity的Activity對象)函數
ps:經過provide註解 ,dagger2 會找到被標記了@Provides註解的方法,並調用其構造方法來完成對象的建立
6、dagger2的補充知識
同ButterKnife 依賴注入框架同樣 dagger2也是採用了apt代碼自動生成技術,註解停留在編譯時,不影響性能。
在編譯器build 過程當中,APT 也就是dagger-compiler 掃描到註解生成對應的class字節碼文件好比掃描到@Provide
就會生成對應的 provide_factory ,來再須要被初始化的時候查找響應的構造方法。
(一) 一些經常使用的dagger2的使用
一、帶一個參數的構造參數
示例:
public class Product(){
@Inject
public product(){}
}
public class Factory{
Product product;
@Inject
public Factory(Product product){
this.product = product;
}
}
解析:在 xxActivity 中進行 inject() 的時候,發現 Factory 的構造函數被 @Inject 標註了且帶有一個參數,而後 dagger2 就去尋找 Product 發現它的構造函數也被 @Inject 標註而且無參數,因而 dagger2 把 Product 的實例注入給 xxActivity,而後再去實例化 Factory 的時候用的是已經注入給 xxActivity 的那個 Product 實例。也就是說咱們能夠這樣理解:並非 Factory 直接實例化 Product,而是 xxActivity 實例化 Product 後交給 Factory 使用的。
二、帶Module的Inject方式
以第三方庫爲OkHttp爲例:直接上修改後的代碼
@Module
public class HttpActivityModule{
@Provides
OkHttpClient provideOkHttpClient(){
return new OkHttpClient();
}
}
@Component (modules =HttpActivityModule.class)
public interface HttpActivityComponent{
void inject(HttpActivity httpActivity);
}
三、帶複雜 Module的Inject方式
使用場景:
在使用dagger2的時候傳入一些配置,直接使用module的構造參數傳入便可。實例化的時候使用的是builder內部類傳入須要的值。
Module中其中一個依賴又要依賴另一個依賴。若是被@Provides標註的方法帶有參數,dagger2會自動尋找本Module中其餘返回值類型爲參數的類型的且被@Provides標註的方法。
@Module
public class HttpActivityModule{
private int txtSize;
public HttpActivityModule(int txtSize){
this.txtSize = txtSize;
}
@Provides
OkHttpClient provideOkHttpClient(){
OkHttpClient client = new OkHttpClient();
client.setTxtSize(this.txtSize);
return client;
}
@Provides
RetrofitManager provideRetrofitManager( OkHttpClient client){
return new RetrofitManager(client);————return new 誰就在Activity中 @Inject誰
}
}
若是本Module中找不到就會去看這個類的構造參數是否被@Inject標註:
public class OkHttpClient {
private int txtSize;
@Inject
public OkHttpClient(){}
}
@Module
public class HttpActivityModule{
private int txtSize;
public HttpActivityModule(int txtSize){
this.txtSize = txtSize;
}
...
@Provides
RetrofitManager provideRetrofitManager( OkHttpClient client){
return new RetrofitManager(client);————return new 誰就在Activity中 @Inject誰
}
四、Component 依賴Component 模式
有時候一個Component 跟另一個Component 所提供的依賴有重複的時候,這時候能夠像操做extends關鍵字同樣進行依賴關係的注入
a、dependence 方式
@Component(modules = HttpActivityModule.class)
public interface HttpActivityComponent{
RetrofitManager provideRetrofitManager();
}
@Component(dependences =HttpActivityComponent.class)
public interface HttpFragmentComponent{
void inject(HttpFragment httpFragment);
}
在Activity中的關鍵代碼:
private HttpActivityComponent httpActivityComponent;//實例化component對象
在onCreate()中:
httpActivityComponent = DaggerHttpActivityComponent.builder().
.httpActivityModule( new HttpActivityModule (this) )
.build();
public HttpActivityComponent getHttpActivityComponent(){
return httpActivityComponent;
}
在對應的fragment中的關鍵代碼:
@Inject
RetrofitManager retrofitManager;
在onViewCreated()中關鍵代碼:
HttpActivityComponent activityComponent=((HttpActivity) getActivity()).getHttpActivityComponent();
DaggerHttpFragmentCompent
.builder()
.httpActivityComponent(activityComponent)
.build()
.inject(this);
小結:
一、在父Component中要顯示的寫出須要暴露可提供給子Component的依賴
二、在子Component的註解中使用 :(dependences =父類Component.class)
三、在子Component的實例化 void inject(xxx)
b、subComponent 方式
部分代碼同a方式同樣進行省略操做,展現不一樣地方:
@Component(modules = HttpActivityModule.class)
public interface HttpActivityComponent{
HttpFragmentComponent httpFragmentComponent();
}
@SubComponent -真實實現inject()
public interface HttpFragmentComponent{
void inject(HttpFragment httpFragment);
}
在對應的fragment中的關鍵代碼:
HttpActivityComponent activityComponent=
((HttpActivity) getActivity()).getHttpActivityComponent()
.httpFragmentComponent().inject(this);
subComponent 實現方式總結
一、先定義子Component,使用@SubComponent標註
二、定義父Component,在其中定義獲取子Component的方法
三、注意子Component 實例化方式
思考:若是子Component構建時候不是無參的而是有參數的狀況,又該如何進行處理呢?
解析重點:子Component構建時候傳入參數的話,就須要在Component中使用@Subcomponent.Builder註解(接口or抽象類)
示例:
父Component:
@Component( modules = {AppModule.class})
public interface AppComponent{
XxActivityComponent.XxBuilderxxBuiler();
}
子Component:
@Subcomponent ( modules = {XxActivityModule.class})
public interface XxActivityComponent{
void inject( XxActivity activity);
@Subcomponent.Builder
interface XxBuilder{
XxBuilder xxActivityModule(XxActivityModile module);
XxActivityComponent build();
}
}
Module 類:
@Module
public class AppModule{
@Provides
AppBen provideAppBean(){
return new AppBean():
}
@Module
public class XxActivityModule{
private ActivityBean activityBean;
public XxActivityModule (ActivityBean bean){
this.activityBean = bean;
}
@Provides
ActivityBean provideActivityBean(){
return this.activityBean;
}
}
而後看一下在其對應的Application 和Activity 裏的實現
App extends Application{ //applicaation 對應了父Component
private AppComponent appComponent;
@Override
public void onCreate(){
appcComponent= DaggerAppComponent.create();
}
public AppComponent getAppComponent(){
return appComponent;
}
}
XxActivity extends AppCompatActivity{
@Inject
AppBean appBean;
@Inject
ActivityBean activityBean;
…
... onCreate(){
…
((App)getApplication() ) .getAppComponent()
.xxBuilder()
.xxActivityModule (new XxActivityModule (new ActivityBean() ) )
.build()
.inject (this);
…
}
小結:
subComponent 實現方式小結:
一、在子Compoonent ,定義一個藉口或是抽象類(一般定義爲xxBuilder),使用@Subcomponent.Builder() 標註
二、編寫返回值 爲XxBuilder,方法的參數須要傳入參數的XxModule類型
三、編寫返回值爲當前子Component 的無參方法
四、 父Component 中定義獲取子 Component.Builder的方法
(二) dagger2 中有關Scope 做用域
一、無module 的狀態
只須要提供依賴的類,以及Component 都添加@Singleton標註
@Singleton
public class Product {
@Inject
public Product(){}
}
@Singleton
@Component
public interface Factory{
void inject(xxActivity activity);
}
在使用的時候,在對應的Activity裏進行聲明:
@Inject
Product product;
DaggerXxActivityComponent.create().inject)the);
ps:
若是使用@Singleton 標註了構造參數 ,或是隻標註了提供依賴的類 並無標註Component類 那麼 系統會報如下兩種錯誤:
@Scope annotations are not allowed on @Inject constructors.Annotate the class instead
@包名 .xxComponent (unscoped) may not reference…@Singleton class ….
二、有module 的狀態
Component 必須添加@Singleton 標註,再根據須要給Module中的@Provides標註的方法再標註上@Singleton
//無參數構造方法
public class Product{
public Product(){}
}
//Component 接口類:
@Singleton
@Component (modules = XxActivityModule.class)
public interface XxActivityComponent{
void inject(XxActivity activity);
}
@Module
public class XxActivityModule{
@Singleton
@Provides
Product provideProduct(){
return new Product():
}
}
有關Scope 的注意事項:
一、把Scope簡單的解釋爲單例是不科學的。正確的理解應該是:
在某個範圍裏他是單例(何爲做用域呢?能夠看做是程序中實例化的Component 的生命週期的長短;
若是在Application裏 build的那它的做用域就是整個App的生命週期;
若是在Activity中build的那它的做用域就隨着Activity的生命週期保持一致;
)
二、Scope 只是一個標註 ,只跟它使用的地方及Component實例化的地方有關
三、在Component 依賴Component 的時候,Scope的名字必須不一樣。
7、dagger2 結合 MVP 模式的小示例片斷詳解
在普通模式下 使用MVP 模型,P層 和V層 也就是Activity會相互持有對方的引用,以下:
View層 實例代碼:
public class PopActivity extends AppCompatActivity implements xxViewImpl {
private xxPresenter xxxPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//實例化p層對象,將View傳遞給P對象,並調用P層方法
xxxPresenter = new xxPresenter(this);
xxxPresenter.xxx();
}
}
Presenter層實例代碼:
public class xxPresenter {
//View層的引用
private xxViewImpl mView;
public xxPresenter(xxViewImpl view) {
mView = view;
}
public void xxx(){
//調用model數據層方法,加載數據
...
//回調方法在成功 or 失敗時候
mView.updateUi();
}
}
以上實例代碼就存在Activity和Presenter 存在必定的耦合程度,若是使用依賴注入的形式的話:
View層僞代碼:
public class xxActivity extends AppCompatActivity implements xxViewImpl{
@Inject
xxPresenter xxxPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
//依賴注入框架初始化
DaggerXXComponent.builder()
.XXModule(new XXModule(this))
.build()
.inject(this);
//調用p層方法
xxxPresenter.xx*();
}
}
tips:代表xxPresenter是須要注入到這個Activity中,即代表這個Activity依賴於xxPresenter,可是p對象不能爲private修飾符。這裏經過new XXModule(this)將view傳遞到XXModule裏,而後XXModule裏的provideXXView()方法返回這個View,當去實例化XXPresenter時,發現構造函數有個參數,此時會在Module裏查找提供這個依賴的方法,將該View傳遞進去,這樣就完成了presenter裏View的注入。
P層僞代碼:
public class xxPresenter {
//View層的引用
xxViewImpl mView;
@Inject
public xxPresenter(xxViewImpl view) {
mView = view;
}
public void xxx(){
//調用model數據層方法,加載數據
...
//回調方法在成功 or 失敗時候
mView.updateUi();
}
}
tips:在P層構造方法添加@Inject註解,代表這個構造方法與Activity中的p層對象創建聯繫。也就說檔某個類被@Inject,就會到這個類中的構造方法中,查找從而完成依賴注入。
注意⚠️:google不推薦直接將P層的構造參數添加註解,更加推薦將P層放到Module裏進行管理,由於這樣代碼更加容易管理。
新建用於連接的牆梁接口
@Component(modules=XXModule.class )
public interface XXComponent{
void inject(xxActivity activity);
}
tips:根據Component將前面兩項創建聯繫,並自定義void 返回類型的方法傳入須要被注入的類Activity。並進行build項目
@Module註解的僞代碼:
@Module
public class XXModule {
final xxViewImpl mView;
public XXModule(xxViewImpl view) {
mview = view;
}
@Provides
XXView provideXXVIew(){
return mView;
}
}
tips:用來提供依賴,來使得部分沒有構造函數的類的依賴,也就是沒法手動@Inject的類好比引用庫,系統庫;
在module類裏,在構造方法裏將外界傳進來的view賦值給聲明的成員對象,並經過@Provides註解標註,以providexx開頭名稱,並返回聲明的view對象,該方法是爲了提供依賴,能夠建立多個不一樣的方法提供不一樣依賴
下面經過僞代碼實例再研究下其原理性的內容:
在對已經@Inject 修飾過的構造方法進行makeProgram 過程後,會生成xxx_Factory類:
public XXPresenter_Factory(Provider<xxViewImpl> viewProvider) {
assert viewProvider != null;
this.viewProvider = viewProvider;
}
@Override
public xxPresenter get() {
return new xxPresenter(viewProvider.get());
}
public static Factory<XXPresenter> create(Provider<XXViewImplw> viewProvider) {
return new XXPresenter_Factory(viewProvider);
}
能夠看到參數是一個Provider類型,範型參數是View層 ,經過構造方法對viewProvider進行實例化。成員參數沒有直接用xxViewImpl 而經過Provider類型修飾是由於前者是一個依賴,而依賴提供者是XXModule,所以這個viewProvider也是由XXModule提供的
下面的get()函數內,也能夠看到,在這裏實例化了xxPresenter對象 經過new xxPresenter(依賴的xxViewImpl,只是是經過get()函數獲取的)
最後經過create()函數,將含有一個參數viewProvider用來建立 XXPresenter_Factory類
接下來再來看一下,XXModule類對應的注入類
public final class XXModule_ProvideMainViewFactory implements Factory<xxViewImpl> {
private final XXModule module;
public XXModule_ProvideXXViewFactory(XXModule module) {
assert module != null;
this.module = module;
}
@Override
public xxViewImpl get() {
return Preconditions.checkNotNull(
module.provideXXView(), "Cannot return null from a non-@Nullable @Provides method");
}
public static Factory<xxViewImpl> create(XXModule module) {
return new XXModule_ProvideXXViewFactory(module);
}
}
在Module類中被@Provides修飾的方法都會對應的生成一個工廠類。這裏是XXModule_ProvideXXViewFactory,
咱們看到這個類裏有一個get()方法,其中調用了XXModule裏的provideXXView()方法來返回咱們所須要的依賴xxViewImpl。還記得在xxPresenter_Factory裏的get()方法中,實例化XXPresenter時候的參數viewProvider.get()嗎?到這裏咱們就明白了,原來那個viewProvider就是生成的XXModule_ProvideXXViewFactory,而後調用了其get()方法,將咱們須要的xxViewImpl注入到XXPresenter裏。
思考:xxPresenter_Factory的建立是由create()完成的,可是這個create是在什麼位置調用的?
答案顯而易見確定是在橋樑類Component 注入類中完成的。
示例僞代碼:
public final class DaggerXXComponent implements XXComponent {
private Provider<xxViewImpl> provideXXViewProvider;
private Provider<XXPresenter> XXPresenterProvider;
private MembersInjector<XXActivity> XXActivityMembersInjector;
private DaggerXXComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
在initialize()函數中,能夠看到三個create()方法,每個provider工廠都對應一個providerFactory.craete()實例,將providerXXViewProvider做爲參數傳遞給XXPresenterProvider,後又又做爲參數傳遞給Activity的注入類:XXActivityMembersInjector對象進行實例化。
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.provideXXViewProvider = XXModule_ProvideXXViewFactory.create(builder.XXModule);
this.XXPresenterProvider = XXPresenter_Factory.create(provideXXViewProvider);
this.XXActivityMembersInjector = XXActivity_MembersInjector.create(XXPresenterProvider);
}
從僞代碼中能夠看出 ,定義的xxComponent會生成一個對應的DaggerXXComponent類,而且該類實現了XXComponent接口裏的方法。
@Override
public void inject(XXActivity activity) {
XXActivityMembersInjector.injectMembers(activity);//將Activity注入到該類中
}
public static final class Builder {
private XXModule XXModule;
private Builder() {}
public XXComponent build() {
if (xxModule == null) {
throw new IllegalStateException(XXModule.class.getCanonicalName() + " must be set");
}
return new DaggerXXComponent(this);
}
public Builder XXModule(XXModule XXModule) {
this.XXModule = Preconditions.checkNotNull(XXModule);
return this;
}
}
}
從僞代碼中發現,Builder內部類就是用來建立module以及自身實例的,因此放在了DaggerXXComponent裏進行初始化依賴,而真正讓依賴關聯起來的就是xxActivityMembersInjector對象。
public final class XXActivity_MembersInjector implements MembersInjector<XXActivity> {
private final Provider<XXPresenter> XXPresenterProvider;
public XXActivity_MembersInjector(Provider<XXPresenter> XXPresenterProvider) {
assert XXPresenterProvider != null;
this.XXPresenterProvider = XXPresenterProvider;
}
public static MembersInjector<XXActivity> create(
Provider<XXPresenter> XXPresenterProvider) {
return new XXActivity_MembersInjector(XXPresenterProvider);
}
@Override
public void injectMembers(XXActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.XXPresenter = XXPresenterProvider.get();
}
public static void injectXXPresenter(
XXActivity instance, Provider<XXPresenter> XXPresenterProvider) {
instance.XXPresenter = XXPresenterProvider.get();
}
}
從這裏發現,將xxPresenterProvider中建立好的xxPresenter實例賦值給instance的成員xxPresenter。這樣用@Inject標註的xxPresenter就獲得了實例化了,進而在代碼中進行實際使用。
小結:
本章部份內容摘自:
感謝分享 respect
結語:
儘量的達到高內聚低耦合的目標,正是呆哥兔追求的意義。
8、dagger2的擴展延伸-dagger.android
用於android的注入方式:
@Component( modules = {AndroidInjectionModule.class,AppModule.class})
public interface AppComponent {
void inject(App app);
}
@Subcomponent (modules = {MainActivityModule.class})
public interface MainActivityComponent extends AndroidInjector<MainActivity>{
void inject(MainActivity activity);
@Subcomponent.Builder
public abstrace class Builder extends AndroidInjector.Builder<MainActivity>{}
}
注意:
- 在父Module中添加 @Module(subcomponents ={子Component})方式進行關聯
- 在這樣的狀況下,子Component中必須存在被@Subcomponent.Builder標註的抽象類或是接口,不然會報異常
@Module
public class MainActivityModule{
@Provides
ActivityBean provideActivityBean(){
return new ActivityBean():
}
}
@Module (subcomponents = {MainActivityComponent.class});
public abstract class AppModule{
@Provides
static AppBean provideAppBean(){
return new AppBean():
}
@Binds
@IntoMap
@ActivityKey( MainActivity.class)
abstract AndroidInjector.Factory
<? extends Activity>bindFactory(MainActivityComponent).inject(this);
在Activity中的實現:
public class App extends Application implements HasActivityInjector{
@Inject
DispatchingAndroidInjector<Activity> activityInjector;
@Override
public void onCreate(){
DaggerAppComponent.create().inject(htis):
}
@Override
public AndroidInjector<Activity> activityInjector(){
return activityInjector;
}
}
public class MainActivity extends AppCompatActivity {
@Inject
AppBean appBean;
@Inject
ActivityBean activityBean;
@Override
protected void onCreate(Bundle saveInstanceState){
AndroidInjection.inject(this);
super.onCreate(saveInstanceState);
….
}
}
dagger.android 小結
一、在AppComponent中將dagger2庫裏的AndroidInjectionModule注入到Applicaation中,並將Application實現響應的接口,並返回響應的方法;
二、子Component繼承自AndroidInjector,內部BUilder使用抽象類並繼承AndroidInjector.Builder;
三、父 Module 使用 @Module ( subcomponents = {} ) 的方式關聯子 Component,並在父 Module 中編寫返回值爲 AndroidInjector.Factory、參數爲子 Component.Builder 的抽象方法(若是有其餘被 @Provides 標註的方法,應將方法改成 static,不然報錯);
四、最後在 Acitivity 的 onCreate() 中第一行代碼的位置使用 AndroidInjection 注入,若是是 Fragment 則是在 onAttach() 方法中,其餘的請自行查閱。
五、dagger.android 庫也提供了其餘實現方式,諸如DaggerApplication、DaggerActivity、DaggerFragment、DaggerService、DaggerBroadcastReceiver 等實現類,有興趣的小夥伴本身研究一下吧