一句話:一款快速的注解框架,應(yīng)用于Android、Java,由 Google 開發(fā)和維護(hù),是 Square 的 Dagger 項(xiàng)目的分支。
目前創(chuàng)新互聯(lián)已為近1000家的企業(yè)提供了網(wǎng)站建設(shè)、域名、網(wǎng)站空間、網(wǎng)站運(yùn)營、企業(yè)網(wǎng)站設(shè)計(jì)、羅城網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長,共同發(fā)展。
gitHub:https://github.com/google/dagger
Dagger2采用依賴注入方式,依賴注入是一種面向?qū)ο蟮木幊棠J?,它的出現(xiàn)是為了降低耦合性,所謂耦合就是類之間依賴關(guān)系,所謂降低耦合就是降低類和類之間依賴關(guān)系。
Java的面向?qū)ο缶幊烫匦?,通常會在一個(gè)Java對象中引用另一個(gè)Java對象,舉例說明一下:
public class ClassA { private ClassB classB; public ClassA(){ classB =new ClassB(); } public void doSomething(){ classB.doSomething(); } }
通過上面的例子可以看出,ClassA需要借助ClassB才能完成一些特定操作,但是我們在ClassA直接實(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 { @Inject ClassB classB; public ClassA() { } public void doSomething() { classB.doSomething(); } }
Dagger2采用的就是注解注入的方式,然后編譯自動生成目標(biāo)代碼的方式實(shí)現(xiàn)宿主與被依賴者之間的關(guān)系。
在Android中的使用方式很簡單:只需在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和注入的橋梁
以項(xiàng)目中實(shí)際場景緩存管理為例,來體驗(yàn)一下解耦效果。設(shè)計(jì)遵循單一職責(zé)原則。
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(); } }
LCacheModule類
@Modulepublic class LCacheModule { /** * 提供緩存對象 * @return 返回緩存對象 */ @Provides @Singleton LCache provideLCache() { return new LCache("lcj",500); } }
LExecutorModule類
@Modulepublic class LExecutorModule { /** * 提供app 多任務(wù)最少維護(hù)線程個(gè)數(shù) * @return 返回多任務(wù)最少維護(hù)線程個(gè)數(shù) */ @Provides @Singleton LExecutor provideLExecutor() { return new LExecutor(10); } }
@Component(modules = {LCacheModule.class,LExecutorModule.class}) @Singletonpublic interface LCacheComponent { LCache lCache(); // app緩存 LExecutor lExecutor(); // app多任務(wù)線程池 void inject(LCacheManager lCacheManager); }
/** * 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() { @Override public void run() { cacheComponent.lCache().saveCache(key,value); } }); } public void readCache(final String key){ cacheComponent.lExecutor().runTask(new Runnable() { @Override public void run() { cacheComponent.lCache().readCache(key); } }); } }
LCacheManager.getInstance().saveCache("key","who is lcj ?");
看下打印結(jié)果:
通過Dagger2的方式剛開始可能會覺得突然間一個(gè)簡單的事情,變得復(fù)雜了,其實(shí)沒有,通過Dagger2很好的處理好了依賴關(guān)系,具體說明,比如我們緩存LCache需要添加一個(gè)最大緩存?zhèn)€數(shù)變化,如果按照之前的方式,我們首先需要對LCache進(jìn)行修改,比如修改構(gòu)造函數(shù)增加maxCacheSize,然后必須對LCacheManager進(jìn)行修改,現(xiàn)在通過Dagger2的方式的話,我們只需修改LCacheModule就可以了,LCache實(shí)例化和相關(guān)參數(shù)和LCacheManager之間并沒有太大的依賴關(guān)系。
基于上面的緩存處理需求,我們需要實(shí)現(xiàn)讀寫分別使用不同的多任務(wù)LExecutor,并且LExecutor的最小線程數(shù)為5,我們會在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 @Singleton LExecutor provideLExecutor() { return new LExecutor(10); } /** * 提供app 多任務(wù)最少維護(hù)線程個(gè)數(shù) * @return 返回多任務(wù)最少維護(hù)線程個(gè)數(shù) */ @Provides @Singleton LExecutor 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")即可。
對于Module的provide函數(shù)也是可以傳遞參數(shù)的,不過需要在當(dāng)前Module中需要提供相關(guān)的參數(shù)的函數(shù)。例如:LCacheModule可以修改如下:
@Modulepublic class LCacheModule { /** * 提供緩存對象 * @return 返回緩存對象 */ @Provides @Singleton LCache provideLCache( @Named("LCache")String name , @Named("LCache")int maxCacheSize) { return new LCache(name,maxCacheSize); } /** * 提供緩存對象 * @return 返回緩存對象 */ @Provides @Singleton @Named("LCache") String provideLCacheName() { return "lcjCache"; } /** * 提供緩存對象 * @return 返回緩存對象 */ @Provides @Singleton @Named("LCache") int provideLCacheMaxSize() { return 600; } }
這里又使用了別名@Name也是因?yàn)闉榱吮苊鈈ound multiple times錯(cuò)誤導(dǎo)致編譯失敗,在編譯的過程中Dagger2會自動去尋找相關(guān)參數(shù)進(jìn)行綁定依賴關(guān)系。