(個人學習筆記)
作用:對象的管理,降低程序耦合。
框架類型:Dagger2是一個依賴注入框架。
性能:Dagger2的註解框架採用的是apt代碼自動生成技術,註解停留在編譯階段,所以說不影響性能。
主要常用標識:@Inject,@Component,@Module,@Provides,@SubComponent,@SingleTon,modules,dependiences。
*ButterKnife也是一種註解框架,採用的也是apt代碼自動生成技術。
看了很多次Dagger2,但是從入門到放棄N多次。下面來總結一下Dagger2的一些用法,現在Dagger2,Annotation,ButterKnife這種註解。
首先我們來看下面這張關係圖。這就是Dagger2的使用模式。通過一個@componet這個橋樑,我們大大的提升了程序的解耦性。
假設有6,7個地方需要使用A.class對象。但此時A對象的構造數,增加或減少一個或者N個參數。以往的做法,我們會挨個兒在new了A.class的地方去修改對象。但現在我們只需要修改A.class本身就好了。*不同的情況,改變的位置也不盡相同
根據上面這張關係圖,來一份無參的案例。(主要是對@Inject,@Componet 註解的使用)
1.A.class類
public class NoParam {
@Inject
public NoParam() {
}
}
2.B.interface
@Component
public interface NoParamComponet {
//指定要注入的目標NoParamActivity
void inject(NoParamActivity noParamActivity);
}
3.C.Activity 值得注意的是:@Inject的對象不可用private修飾,要用public或者protect。
public class NoParamActivity extends Activity {
@Inject
protected NoParam noParam;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_doublewave);
//觸發dagger注入機制
DaggerNoParamComponet.create().inject(this);
Toast.makeText(this, "結果="+noParam.hashCode(), Toast.LENGTH_SHORT).show();
}
}
有參數的案例
1.參數對象一InsiceParam
public class InsideParam {
@Inject
public InsideParam() {
}
}
2.參數對象二HaveParam。包含參數一
public class HaveParam {
@Inject
protected InsideParam insideParam;
public HaveParam(InsideParam insideParam) {
this.insideParam = insideParam;
}
}
3.B.interface(Component對象)
@Component
public interface HaveParamComponet {
void inject(HaveParamActivity haveParamActivity);
}
4.C.activity(調用對象)
public class HaveParamActivity extends Activity {
@Inject
protected HaveParam haveParam;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_dagger_student);
DaggerHaveParamComponet.create().inject(this);
Toast.makeText(this,"結果="+haveParam.hashCode()+
haveParam.insideParam.hashCode(),Toast.LENGTH_LONG).show();
}
}
這裏有一點值得注意,在HaveParam裏面的時候,並沒有對InsideParam做create().inject()的操作來完成注入。那到底是誰幫我們把InsideParam完成操作了呢?
答案:是HaveParamActivity對InsideParam完成了注入操作。
解釋:在HaveParamActivity裏面,在進行inject對象HaveParam的時候發現HaveParam的構造函數被inject標註,且帶有一個參數,於是Dagger2去尋找InsideParam,它的構造參數被@Inject標註且無參數。於是Dagger2把InsideParam注入給HaveParamActivity。再去實例化的時候用的是已經注入給HaveParamActivity的那個InsideParam實例。
分析結果:HaveParamActivity將InsideParam實例化,將實例化後的InsideParam拿去給HaveParam使用。
調用第三方類庫對象
上面是我們自己定義的對象類,那如何調用第三方類庫的對象?(主要是@Module,@Provides的使用)
案例如下:
1.HttpModule(這裏使用了@Module和@Provides。)
@Module的作用:我們需要注入的類是第三方類庫,我們無法再構造函數直接加@Inject註解,還有一個問題就是如果有多個構造函數的問題,Module封裝依賴就是爲了解決這些問題。
@Provides作用:標註@Module中能夠提供實例化的方法。
@Module
public class HttpMudule {
@Provides
OkHttpClient providerHttpClient(){
return new OkHttpClient();
}
}
2.Component
使用@Component標註這個接口,並使用modules=的方法鏈接上第一步中編寫的Module類(連接HttpMudule類);
@Component(modules = HttpMudule.class)
public interface HttpModuleComponet {
void inject(HttpActivity httpActivity);
}
3.HttpActivity
public class HttpActivity extends Activity {
@Inject
protected HttpMudule httpMudule;
@Override
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
setContentView(R.layout.layout_doublewave);
DaggerHttpModuleComponet.create().inject(this);
Toast.makeText(this, "結果="+httpMudule.hashCode(), Toast.LENGTH_SHORT).show();
}
}
Module中的@Provides含參,且參數依賴另外的@Provides返回值
先邏輯分析這個過程:
第一步:在Module內尋找,@Provides方法返回值=含有參數的@Provides的參數值。
第二步:如果第一步中沒有在Module中找到那個返回值的@Provides方法。則去看這個類的構造函數是否被@Inject標註
由此可得:一般情況下,Module中方法返回值都不能相同。但有辦法使其返回值相同。
案例如下:
@Module
public class HttpMudule {
private int num;
public HttpMudule(int num) {
this.num=num;
}
@Provides
OkHttpClient providerHttpClient(int num){
OkHttpClient okHttpClient=new OkHttpClient();
okHttpClient.setTimeSize(this.num);
return okHttpClient;
}
@Provides
RetrofitDemo providerRetrofit(OkHttpClient okHttpClient){
return new RetrofitDemo(okHttpClient);
}
}
HttpActivity的Componet注入則修改爲如下寫法,動態輸入參數num=200。
public class HttpActivity extends Activity {
@Inject
protected HttpMudule httpMudule;
@Override
public void onCreate(Bundle savedInstanceState, PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
setContentView(R.layout.layout_doublewave);
//DaggerHttpModuleComponet.create().inject(this);//之前的寫法
DaggerHttpModuleComponet.builder().httpMudule(new HttpMudule(200)).build().inject(this);//@Module依賴另外的依賴之後的寫法(不一定全是這樣寫)。
Toast.makeText(this, "結果="+httpMudule.hashCode(), Toast.LENGTH_SHORT).show();
}
}
Component和Component之間的依賴關係的實現
類和類之間的依賴有extends來實現,component和Component的依賴由Dependence和subComponent來實現。
1.dependence
邏輯:A.class B.class AComponent(父) BComponent(子) AActivity BActivity
在BComponent中加入dependencies來表明依賴於AComponent。
在AActivity裏面增加一個方法,返回結果爲AComponent對象的方法getAComponent()。
在BActivity裏面注入之前,new一個AComponent,對象=AActivity.getAComponent();
在BActivity注入的時候,用build,可以注入Acommponent。從而使用AComponent的注入,完成依賴。
2.subComponent(wasabi的Part 0... 0...)
HttpFragmentComponent是子。HttpActivityComponent是父。
a.在子Component中加入@Subcomponent標識
b.在父Component中獲得定義子Component的方法。
c.在子Activity注入的時候,Component實例化。
Scope作用域---單例
a.無Module的使用方式。
@Singleton
public class HttpMudule {
OkHttpClient providerHttpClient(){
return new OkHttpClient();
}
}
@Singleton
@Component
public interface HttpModuleComponet {
void inject(HttpActivity httpActivity);
}
Actvity和之前的一樣。就不po了。
結果分析:@Singleton不可以標註構造器。依賴類標註了@Singleton,那麼Component也要標註@Singleton。否則會報錯。
b.帶module的使用方式。
@Module
public class HttpMudule {
@Singleton
@Provides
OkHttpClient providerHttpClient(){
return new OkHttpClient();
}
}
@Singleton
@Component(modules = HttpMudule.class)
public interface HttpModuleComponet {
void inject(HttpActivity httpActivity);
}
其他和上面一樣。
結果分析:@Module內的@Provides需要被標註@Singleton。Component需要被標註上@Singleton
對於@Scope的總結:
在某個範圍裏它是單例(何爲作用域呢,可以看作是我們在程序中實例化的Component的生命週期的長短:如果在Application裏build的那它的作用域就是整個App的生命週期,如果是在Acitivity中build的那它的作用域就跟此Acitivity的生命週期相同,依次類推)。
後續補充......