Android注解使用之Dagger2实现项目依赖关系解耦
一句话:一款快速的注解框架,应用于Android、Java,由 Google 开发和维护,是Square的Dagger项目的分支。
gitHub:https://github.com/google/dagger
Dagger2采用依赖注入方式,依赖注入是一种面向对象的编程模式,它的出现是为了降低耦合性,所谓耦合就是类之间依赖关系,所谓降低耦合就是降低类和类之间依赖关系。
依赖关系Java的面向对象编程特性,通常会在一个Java对象中引用另一个Java对象,举例说明一下:
publicclassClassA{privateClassBclassB;publicClassA(){classB=newClassB();}publicvoiddoSomething(){classB.doSomething();}}
通过上面的例子可以看出,ClassA需要借助ClassB才能完成一些特定操作,但是我们在ClassA直接实例化了ClassB,这样耦合就产生了,第一违背了单一职责原则,ClassB的实例化应该由自己完成,不应该由ClassA来完成,第二违背了开闭原则,一旦ClassB的构造函数产生变化,就需要修改ClassA的构造函数。
通过依赖注入降低这种耦合关系:
1.通过构造参数传参的方式
publicclassClassA{privateClassBclassB;publicClassA(ClassBclassB){this.classB=classB;}publicvoiddoSomething(){classB.doSomething();}}
2.通过set方法的方式
publicclassClassA{privateClassBclassB;publicClassA(){}publicvoidsetClassB(ClassBclassB){this.classB=classB;}publicvoiddoSomething(){classB.doSomething();}}
3.通过接口注入的方式
interfaceClassBInterface{voidsetB(ClassBclassB);}publicclassClassAimplementsClassBInterface{privateClassBclassB;publicClassA(){}@OverridepublicvoidsetB(ClassBclassB){this.classB=classB;}publicvoiddoSomething(){classB.doSomething();}}
4.通过注解注入
publicclassClassA{@InjectClassBclassB;publicClassA(){}publicvoiddoSomething(){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类
/***Createdbylichaojunon2017/3/30.*处理缓存*/publicclassLCache{privatestaticfinalStringDEFAULT_CACHE_NAME="LCache";//默认缓存名字privatestaticfinalintDEFAULT_MAX_CACHE_SIZE=1024;//默认缓存名字privateStringcacheName=DEFAULT_CACHE_NAME;//缓存名字privateintmaxCacheSize=DEFAULT_MAX_CACHE_SIZE;publicLCache(){}@InjectpublicLCache(StringcacheName,intmaxCacheSize){this.cacheName=cacheName;this.maxCacheSize=maxCacheSize;}publicvoidsaveCache(Stringkey,Stringvalue){Log.e(LCacheManager.TAG,"cacheName:="+cacheName);Log.e(LCacheManager.TAG,"maxCacheSize:="+maxCacheSize);Log.e(LCacheManager.TAG,"saveCache:key="+key+"value="+value);}publicvoidreadCache(Stringkey){Log.e(LCacheManager.TAG,"readCache:key:="+key);}}
LExecutor类
publicclassLExecutor{privatestaticfinalintDEFAULT_CPU_CORE=Runtime.getRuntime().availableProcessors();//默认线程池维护线程的最少数量privateintcoreSize=DEFAULT_CPU_CORE;//线程池维护线程的最少数量@InjectpublicLExecutor(intcoreSize){this.coreSize=coreSize;}publicvoidrunTask(Runnablerunnable){if(runnable==null){return;}Log.e(LCacheManager.TAG,"coreSize:="+coreSize);Log.e(LCacheManager.TAG,"runTask");runnable.run();}}
LCacheModule类
@ModulepublicclassLCacheModule{/***提供缓存对象*@return返回缓存对象*/@Provides@SingletonLCacheprovideLCache(){returnnewLCache("lcj",500);}}
LExecutorModule类
@ModulepublicclassLExecutorModule{/***提供app多任务最少维护线程个数*@return返回多任务最少维护线程个数*/@Provides@SingletonLExecutorprovideLExecutor(){returnnewLExecutor(10);}}
@Component(modules={LCacheModule.class,LExecutorModule.class})@SingletonpublicinterfaceLCacheComponent{LCachelCache();//app缓存LExecutorlExecutor();//app多任务线程池voidinject(LCacheManagerlCacheManager);}
/***Createdbylichaojunon2017/3/30.*缓存处理管理*/publicclassLCacheManager{publicstaticfinalStringTAG=LCacheManager.class.getSimpleName();privateLCacheComponentcacheComponent;privatestaticclassSingletonHolder{privatestaticLCacheManagerinstance=newLCacheManager();}privateLCacheManager(){cacheComponent=DaggerLCacheComponent.builder().lCacheModule(newLCacheModule()).build();cacheComponent.inject(this);}publicstaticLCacheManagergetInstance(){returnSingletonHolder.instance;}publicvoidsaveCache(finalStringkey,finalStringvalue){cacheComponent.lExecutor().runTask(newRunnable(){@Overridepublicvoidrun(){cacheComponent.lCache().saveCache(key,value);}});}publicvoidreadCache(finalStringkey){cacheComponent.lExecutor().runTask(newRunnable(){@Overridepublicvoidrun(){cacheComponent.lCache().readCache(key);}});}}
LCacheManager.getInstance().saveCache("key","whoislcj?");
看下打印结果:
通过Dagger2的方式刚开始可能会觉得突然间一个简单的事情,变得复杂了,其实没有,通过Dagger2很好的处理好了依赖关系,具体说明,比如我们缓存LCache需要添加一个最大缓存个数变化,如果按照之前的方式,我们首先需要对LCache进行修改,比如修改构造函数增加maxCacheSize,然后必须对LCacheManager进行修改,现在通过Dagger2的方式的话,我们只需修改LCacheModule就可以了,LCache实例化和相关参数和LCacheManager之间并没有太大的依赖关系。
6.关于@Module提供多个同类型@Provides基于上面的缓存处理需求,我们需要实现读写分别使用不同的多任务LExecutor,并且LExecutor的最小线程数为5,我们会在LCacheComponent添加提供writeLExecutor函数,如下:
@Component(modules={LCacheModule.class,LExecutorModule.class})@SingletonpublicinterfaceLCacheComponent{LCachelCache();//app缓存LExecutorlExecutor();//app多任务线程池LExecutorwriteLExecutor();//app写缓存多任务线程池voidinject(LCacheManagerlCacheManager);}
在LExecutorModule中添加提供依赖初始化的provideWriteLExecutor函数。如下:
@ModulepublicclassLExecutorModule{/***提供app多任务最少维护线程个数*@return返回多任务最少维护线程个数*/@Provides@SingletonLExecutorprovideLExecutor(){returnnewLExecutor(10);}/***提供app多任务最少维护线程个数*@return返回多任务最少维护线程个数*/@Provides@SingletonLExecutorprovideWriteLExecutor(){returnnewLExecutor(5);}}
然后写完之后Rebuild一下项目,以为万事大吉了,结果报了如下错误,
怎么办呢,难道Dagger2就这么不堪一击吗,当然不是解决这个问题很容易,使用@Named注解解决这个问题,我们只需要在LCacheComponent的writeLExecutor()和
LExecutorModule的provideWriteLExecutor()函数上添加相同的@Named("WriteLExecutor")即可。
对于Module的provide函数也是可以传递参数的,不过需要在当前Module中需要提供相关的参数的函数。例如:LCacheModule可以修改如下:
@ModulepublicclassLCacheModule{/***提供缓存对象*@return返回缓存对象*/@Provides@SingletonLCacheprovideLCache(@Named("LCache")Stringname,@Named("LCache")intmaxCacheSize){returnnewLCache(name,maxCacheSize);}/***提供缓存对象*@return返回缓存对象*/@Provides@Singleton@Named("LCache")StringprovideLCacheName(){return"lcjCache";}/***提供缓存对象*@return返回缓存对象*/@Provides@Singleton@Named("LCache")intprovideLCacheMaxSize(){return600;}}
这里又使用了别名@Name也是因为为了避免bound multiple times错误导致编译失败,在编译的过程中Dagger2会自动去寻找相关参数进行绑定依赖关系。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。