Dagger2
? ? 一句話:一款快速的注解框架,應用于Android、Java,由 Google 開發和維護,是?Square?的?Dagger?項目的分支。
? ? gitHub:https://github.com/google/dagger
? ? Dagger2采用依賴注入方式,依賴注入是一種面向對象的編程模式,它的出現是為了降低耦合性,所謂耦合就是類之間依賴關系,所謂降低耦合就是降低類和類之間依賴關系。
依賴關系
? ?Java的面向對象編程特性,通常會在一個Java對象中引用另一個Java對象,舉例說明一下:
public?class?ClassA?{????private?ClassB?classB;????public?ClassA(){classB?=new?ClassB();}????public??void?doSomething(){classB.doSomething();}
}
通過上面的例子可以看出,ClassA需要借助ClassB才能完成一些特定操作,但是我們在ClassA直接實例化了ClassB,這樣耦合就產生了,第一違背了單一職責原則,ClassB的實例化應該由自己完成,不應該由ClassA來完成,第二違背了開閉原則,一旦ClassB的構造函數產生變化,就需要修改ClassA的構造函數。
通過依賴注入降低這種耦合關系:
1.通過構造參數傳參的方式
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采用的就是注解注入的方式,然后編譯自動生成目標代碼的方式實現宿主與被依賴者之間的關系。
Dagger2在Android的使用方式及簡單說明
在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 ?修飾需要依賴的地方(可以是構造方法、field或者一般的方法)
@Component 連接@Module和注入的橋梁
Dagger2舉例說明
?以項目中實際場景緩存管理為例,來體驗一下解耦效果。設計遵循單一職責原則。
?1.首先定義緩存類和多任務類。并且在其構造函數上添加@Inject注解
LCache類
/***?Created?by?lichaojun?on?2017/3/30.*?處理緩存?*/public?class?LCache?{????private?static??final??String?DEFAULT_CACHE_NAME="LCache";//默認緩存名字private?static??final??int?DEFAULT_MAX_CACHE_SIZE=1024;//默認緩存名字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();//默認線程池維護線程的最少數量private?int?coreSize?=?DEFAULT_CPU_CORE;//線程池維護線程的最少數量@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類來提供相關依賴
LCacheModule類
@Modulepublic?class?LCacheModule?{????/***?提供緩存對象*?@return?返回緩存對象?????*/@Provides@SingletonLCache?provideLCache()?{????????return?new?LCache("lcj",500);}}
LExecutorModule類
@Modulepublic?class?LExecutorModule?{????/***?提供app?多任務最少維護線程個數*?@return?返回多任務最少維護線程個數?????*/@Provides@SingletonLExecutor?provideLExecutor()?{????????return?new?LExecutor(10);}
}
3.使用@Component 用來將@Inject和@Module關聯起來,新建LCacheComponent類
@Component(modules?=?{LCacheModule.class,LExecutorModule.class})
@Singletonpublic?interface?LCacheComponent?{LCache?lCache();???//?app緩存LExecutor?lExecutor();??//?app多任務線程池void?inject(LCacheManager?lCacheManager);
}
4.在宿主中注入想要依賴的對象
/***?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.使用場景調用及簡單解說
LCacheManager.getInstance().saveCache("key","who?is?lcj??");
看下打印結果:
通過Dagger2的方式剛開始可能會覺得突然間一個簡單的事情,變得復雜了,其實沒有,通過Dagger2很好的處理好了依賴關系,具體說明,比如我們緩存LCache需要添加一個最大緩存個數變化,如果按照之前的方式,我們首先需要對LCache進行修改,比如修改構造函數增加maxCacheSize,然后必須對LCacheManager進行修改,現在通過Dagger2的方式的話,我們只需修改LCacheModule就可以了,LCache實例化和相關參數和LCacheManager之間并沒有太大的依賴關系。
6.關于@Module提供多個同類型@Provides
?基于上面的緩存處理需求,我們需要實現讀寫分別使用不同的多任務LExecutor,并且LExecutor的最小線程數為5,我們會在LCacheComponent添加提供writeLExecutor函數,如下:
@Component(modules?=?{LCacheModule.class,LExecutorModule.class})
@Singletonpublic?interface?LCacheComponent?{LCache?lCache();???//?app緩存LExecutor?lExecutor();??//?app多任務線程池LExecutor?writeLExecutor();??//?app?寫緩存多任務線程池void?inject(LCacheManager?lCacheManager);
}
在LExecutorModule中添加提供依賴初始化的provideWriteLExecutor函數。如下:
@Modulepublic?class?LExecutorModule?{????/***?提供app?多任務最少維護線程個數*?@return?返回多任務最少維護線程個數?????*/@Provides@SingletonLExecutor?provideLExecutor()?{????????return?new?LExecutor(10);}????/***?提供app?多任務最少維護線程個數*?@return?返回多任務最少維護線程個數?????*/@Provides@SingletonLExecutor?provideWriteLExecutor()?{????????return?new?LExecutor(5);}
}
然后寫完之后Rebuild一下項目,以為萬事大吉了,結果報了如下錯誤,
怎么辦呢,難道Dagger2就這么不堪一擊嗎,當然不是解決這個問題很容易,使用@Named注解解決這個問題,我們只需要在LCacheComponent的writeLExecutor()和
LExecutorModule的provideWriteLExecutor()函數上添加相同的@Named("WriteLExecutor")即可。
對于Module的provide函數也是可以傳遞參數的,不過需要在當前Module中需要提供相關的參數的函數。例如:LCacheModule可以修改如下:
@Modulepublic?class?LCacheModule?{????/***?提供緩存對象*?@return?返回緩存對象?????*/@Provides@SingletonLCache?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也是因為為了避免bound multiple times錯誤導致編譯失敗,在編譯的過程中Dagger2會自動去尋找相關參數進行綁定依賴關系。
轉載于:https://blog.51cto.com/kiujyhgt/1915457
總結
以上是生活随笔為你收集整理的Android注解使用之Dagger2实现项目依赖关系解耦的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。