Dagger2
? ? 一句話:一款快速的注解框架,應(yīng)用于Android、Java,由 Google 開發(fā)和維護(hù),是?Square?的?Dagger?項(xiàng)目的分支。
? ? gitHub:https://github.com/google/dagger
? ? Dagger2采用依賴注入方式,依賴注入是一種面向?qū)ο蟮木幊棠J?#xff0c;它的出現(xiàn)是為了降低耦合性,所謂耦合就是類之間依賴關(guān)系,所謂降低耦合就是降低類和類之間依賴關(guān)系。
依賴關(guān)系
? ?Java的面向?qū)ο缶幊烫匦?#xff0c;通常會(huì)在一個(gè)Java對(duì)象中引用另一個(gè)Java對(duì)象,舉例說明一下:
public?class?ClassA?{????private?ClassB?classB;????public?ClassA(){classB?=new?ClassB();}????public??void?doSomething(){classB.doSomething();}
}
通過上面的例子可以看出,ClassA需要借助ClassB才能完成一些特定操作,但是我們?cè)贑lassA直接實(shí)例化了ClassB,這樣耦合就產(chǎn)生了,第一違背了單一職責(zé)原則,ClassB的實(shí)例化應(yīng)該由自己完成,不應(yīng)該由ClassA來完成,第二違背了開閉原則,一旦ClassB的構(gòu)造函數(shù)產(chǎn)生變化,就需要修改ClassA的構(gòu)造函數(shù)。
通過依賴注入降低這種耦合關(guān)系:
1.通過構(gòu)造參數(shù)傳參的方式
public?class?ClassA?{????private?ClassB?classB;????public?ClassA(ClassB?classB){????????this.classB?=classB;}????public??void?doSomething(){classB.doSomething();}
}
2.通過set方法的方式
public?class?ClassA?{????private?ClassB?classB;????public?ClassA(){}????public?void?setClassB(ClassB?classB)?{????????this.classB?=?classB;}????public??void?doSomething(){classB.doSomething();}
}
3.通過接口注入的方式
interface?ClassBInterface?{????void?setB(ClassB?classB);
}public?class?ClassA?implements?ClassBInterface?{????private?ClassB?classB;????public?ClassA()?{}@Override????public?void?setB(ClassB?classB)?{????????this.classB?=?classB;}????public?void?doSomething()?{classB.doSomething();}
}
4.通過注解注入
public?class?ClassA?{@InjectClassB?classB;????public?ClassA()?{}????public?void?doSomething()?{classB.doSomething();}
}
Dagger2采用的就是注解注入的方式,然后編譯自動(dòng)生成目標(biāo)代碼的方式實(shí)現(xiàn)宿主與被依賴者之間的關(guān)系。
Dagger2在Android的使用方式及簡(jiǎn)單說明
在Android中的使用方式很簡(jiǎn)單:只需在Module的build.gradle中添加一下配置
dependencies?{compile?'com.google.dagger:dagger:2.x'annotationProcessor?'com.google.dagger:dagger-compiler:2.x'}
?Dagger2 annotation講解
@Module 修飾的類專門用來提供依賴
@Provides 修飾的方法用在Module類里
@Inject ?修飾需要依賴的地方(可以是構(gòu)造方法、field或者一般的方法)
@Component 連接@Module和注入的橋梁
Dagger2舉例說明
?以項(xiàng)目中實(shí)際場(chǎng)景緩存管理為例,來體驗(yàn)一下解耦效果。設(shè)計(jì)遵循單一職責(zé)原則。
?1.首先定義緩存類和多任務(wù)類。并且在其構(gòu)造函數(shù)上添加@Inject注解
LCache類
/***?Created?by?lichaojun?on?2017/3/30.*?處理緩存?*/public?class?LCache?{????private?static??final??String?DEFAULT_CACHE_NAME="LCache";//默認(rèn)緩存名字private?static??final??int?DEFAULT_MAX_CACHE_SIZE=1024;//默認(rèn)緩存名字private?String?cacheName=DEFAULT_CACHE_NAME;//緩存名字private?int?maxCacheSize=DEFAULT_MAX_CACHE_SIZE;????public?LCache?(){}@Inject????public??LCache(String?cacheName,int?maxCacheSize){????????this.cacheName=cacheName;????????this.maxCacheSize=maxCacheSize;}????public?void?saveCache(String?key?,String?value){Log.e(LCacheManager.TAG,"cacheName:??=?"+cacheName);Log.e(LCacheManager.TAG,"maxCacheSize:??=?"+maxCacheSize);Log.e(LCacheManager.TAG,"saveCache:?key?=?"+key?+"?value?=?"+value);}????public??void?readCache(String?key){Log.e(LCacheManager.TAG,"readCache:?key:??=?"+key);}
}
LExecutor類
public?class?LExecutor?{????private?static?final?int?DEFAULT_CPU_CORE?=?Runtime.getRuntime().availableProcessors();//默認(rèn)線程池維護(hù)線程的最少數(shù)量private?int?coreSize?=?DEFAULT_CPU_CORE;//線程池維護(hù)線程的最少數(shù)量@Inject????public?LExecutor(int?coreSize)?{????????this.coreSize?=?coreSize;}????public?void?runTask(Runnable?runnable)?{????????if?(runnable?==?null)?{????????????return;}Log.e(LCacheManager.TAG,"coreSize:??=?"+coreSize);Log.e(LCacheManager.TAG,?"runTask");runnable.run();}
}
2.使用@Module分別定義LCacheModule、LExecutorModule類來提供相關(guān)依賴
LCacheModule類
@Modulepublic?class?LCacheModule?{????/***?提供緩存對(duì)象*?@return?返回緩存對(duì)象?????*/@Provides@SingletonLCache?provideLCache()?{????????return?new?LCache("lcj",500);}}
LExecutorModule類
@Modulepublic?class?LExecutorModule?{????/***?提供app?多任務(wù)最少維護(hù)線程個(gè)數(shù)*?@return?返回多任務(wù)最少維護(hù)線程個(gè)數(shù)?????*/@Provides@SingletonLExecutor?provideLExecutor()?{????????return?new?LExecutor(10);}
}
3.使用@Component 用來將@Inject和@Module關(guān)聯(lián)起來,新建LCacheComponent類
@Component(modules?=?{LCacheModule.class,LExecutorModule.class})
@Singletonpublic?interface?LCacheComponent?{LCache?lCache();???//?app緩存LExecutor?lExecutor();??//?app多任務(wù)線程池void?inject(LCacheManager?lCacheManager);
}
4.在宿主中注入想要依賴的對(duì)象
/***?Created?by?lichaojun?on?2017/3/30.*?緩存處理管理*/
public?class?LCacheManager?{public?static??final??String?TAG=LCacheManager.class.getSimpleName();private??LCacheComponent?cacheComponent;private?static?class?SingletonHolder?{private?static?LCacheManager?instance?=?new?LCacheManager();}private?LCacheManager(){cacheComponent?=?DaggerLCacheComponent.builder().lCacheModule(new?LCacheModule()).build();cacheComponent.inject(this);}public?static?LCacheManager?getInstance()?{return?SingletonHolder.instance;}public??void?saveCache(final?String?key?,?final?String?value)?{cacheComponent.lExecutor().runTask(new?Runnable()?{@Overridepublic?void?run()?{cacheComponent.lCache().saveCache(key,value);}});}public??void?readCache(final?String?key){cacheComponent.lExecutor().runTask(new?Runnable()?{@Overridepublic?void?run()?{cacheComponent.lCache().readCache(key);}});}
}
5.使用場(chǎng)景調(diào)用及簡(jiǎn)單解說
LCacheManager.getInstance().saveCache("key","who?is?lcj??");
看下打印結(jié)果:
通過Dagger2的方式剛開始可能會(huì)覺得突然間一個(gè)簡(jiǎn)單的事情,變得復(fù)雜了,其實(shí)沒有,通過Dagger2很好的處理好了依賴關(guān)系,具體說明,比如我們緩存LCache需要添加一個(gè)最大緩存?zhèn)€數(shù)變化,如果按照之前的方式,我們首先需要對(duì)LCache進(jìn)行修改,比如修改構(gòu)造函數(shù)增加maxCacheSize,然后必須對(duì)LCacheManager進(jìn)行修改,現(xiàn)在通過Dagger2的方式的話,我們只需修改LCacheModule就可以了,LCache實(shí)例化和相關(guān)參數(shù)和LCacheManager之間并沒有太大的依賴關(guān)系。
6.關(guān)于@Module提供多個(gè)同類型@Provides
?基于上面的緩存處理需求,我們需要實(shí)現(xiàn)讀寫分別使用不同的多任務(wù)LExecutor,并且LExecutor的最小線程數(shù)為5,我們會(huì)在LCacheComponent添加提供writeLExecutor函數(shù),如下:
@Component(modules?=?{LCacheModule.class,LExecutorModule.class})
@Singletonpublic?interface?LCacheComponent?{LCache?lCache();???//?app緩存LExecutor?lExecutor();??//?app多任務(wù)線程池LExecutor?writeLExecutor();??//?app?寫緩存多任務(wù)線程池void?inject(LCacheManager?lCacheManager);
}
在LExecutorModule中添加提供依賴初始化的provideWriteLExecutor函數(shù)。如下:
@Modulepublic?class?LExecutorModule?{????/***?提供app?多任務(wù)最少維護(hù)線程個(gè)數(shù)*?@return?返回多任務(wù)最少維護(hù)線程個(gè)數(shù)?????*/@Provides@SingletonLExecutor?provideLExecutor()?{????????return?new?LExecutor(10);}????/***?提供app?多任務(wù)最少維護(hù)線程個(gè)數(shù)*?@return?返回多任務(wù)最少維護(hù)線程個(gè)數(shù)?????*/@Provides@SingletonLExecutor?provideWriteLExecutor()?{????????return?new?LExecutor(5);}
}
然后寫完之后Rebuild一下項(xiàng)目,以為萬事大吉了,結(jié)果報(bào)了如下錯(cuò)誤,
怎么辦呢,難道Dagger2就這么不堪一擊嗎,當(dāng)然不是解決這個(gè)問題很容易,使用@Named注解解決這個(gè)問題,我們只需要在LCacheComponent的writeLExecutor()和
LExecutorModule的provideWriteLExecutor()函數(shù)上添加相同的@Named("WriteLExecutor")即可。
對(duì)于Module的provide函數(shù)也是可以傳遞參數(shù)的,不過需要在當(dāng)前Module中需要提供相關(guān)的參數(shù)的函數(shù)。例如:LCacheModule可以修改如下:
@Modulepublic?class?LCacheModule?{????/***?提供緩存對(duì)象*?@return?返回緩存對(duì)象?????*/@Provides@SingletonLCache?provideLCache(?@Named("LCache")String?name?,?@Named("LCache")int?maxCacheSize)?{????????return?new?LCache(name,maxCacheSize);}????/***?提供緩存對(duì)象*?@return?返回緩存對(duì)象?????*/@Provides@Singleton@Named("LCache")String?provideLCacheName()?{????????return?"lcjCache";}????/***?提供緩存對(duì)象*?@return?返回緩存對(duì)象?????*/@Provides@Singleton@Named("LCache")????int?provideLCacheMaxSize()?{????????return?600;}}
這里又使用了別名@Name也是因?yàn)闉榱吮苊鈈ound multiple times錯(cuò)誤導(dǎo)致編譯失敗,在編譯的過程中Dagger2會(huì)自動(dòng)去尋找相關(guān)參數(shù)進(jìn)行綁定依賴關(guān)系。
轉(zhuǎn)載于:https://blog.51cto.com/kiujyhgt/1915457
總結(jié)
以上是生活随笔為你收集整理的Android注解使用之Dagger2实现项目依赖关系解耦的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。