网上都说Dagger2是比较难上手的,我在看了大量资料和使用时也遇到了不少不懂或者模糊的知识点,并且大部分博客资料都比较古老。忽然有那么一瞬间,忽然明白了因此然,故总结了4篇文章。话说在java中使用仍是很繁琐的,不要怕带你真正上手,并运用到咱们的Android项目中去。java
本次Dagger2讲解总共分4篇:
一、Dagger2基础知识及在Java中使用(1)
二、Dagger2基础知识及在Java中使用(2)
三、Dagger2进阶知识及在Android中使用
四、Dagger2华丽使用在MVP框架中android
首先简单申明下,Dagger2的好处不是本文的重点。你们能够自行百度。Dagger2是依赖注解框架,像咱们之间的butterknife也是这样的框架,想这样的框架依赖通常都有2行。第二行是以annotationProcessor开头的。这实际上是apt的工具,并且这样的依赖注解框架不会影响性能(不是反射机制),在编译的时候,apt把要用的代码生成。因此大可放心使用
再举我理解的例子(你们不要全信,哈哈稍微不恰当):@Component至关于一个注射器(记住是接口);@Module至关于注射液,就是数据源(记住这里是类或者抽象类),此时要把注射液放入指定哪一个注射器如:@Component( modules = ... );@Inject 至关于标注被注射体。git
以后的讲解都是走完简单的流程,实现功能,而后讲大概理解。贴在博客上的代码,可能会省略部分代码,便于理解。github上的Demo及注释,很是详细,接近完美0-0#
若是是彻底没了解过,关于Dagger一些标注的具体介绍和理解,推荐这里有3篇介绍标注的意思和怎么工做的github
implementation 'com.google.dagger:dagger:2.24'
annotationProcessor "com.google.dagger:dagger-compiler:2.24"
复制代码
首先随便定义个类:Person,无参构造方法用@Inject标注:bash
public class Person {
@Inject
public Person() {
}
}
复制代码
@Component
public interface AstudyActivityComponent {
void injectTo(AstudyActivity astudyActivity);
}
复制代码
作好上面步骤后,点开studio里build标签下的Make Project。让apt帮咱们生成代码,通常生成代码为Dagger+你定义Component的类名。
以后这个步骤再也不重复,就是你写完准备代码的时候必定要让apt生成代码,Make Project下
而后在咱们的Activity里:app
public class AstudyActivity extends BaseActivity {
@Inject
Person person;
@Override
//这里是我封装的onCreate,省略部分代码,只为理解,以后都请忽略!
protected void processLogic() {
//第一种
DaggerAstudyActivityComponent.create().injectTo(this);
//第二种
//DaggerAstudyActivityComponent.builder().build().injectTo(this);
}
}
复制代码
在咱们的Activity里build下咱们的Component,而后注册在咱们的Activity里,就可使用经过咱们的@Inject使用咱们的person了。
这里初始化有2种:
一、DaggerAstudyActivityComponent.create().injectTo(this);
二、DaggerAstudyActivityComponent.builder().build().injectTo(this); 这个使用module传值必定要使用框架
那么一个简单的使用就实现了,这里忽略了new的过程,从这个过程就知道他解耦的实现了。ide
为何会有module的概念,好比上面的Person的构造方法能够用@Inject标注,可是引入的第三方库但是没有办法加的,因此这里使用@Module能够解决这个问题。
这里咱们定义个Human,伪装他是第三方类库,里面没有使用@Inject函数
public class Human {
public Human() {
}
}
复制代码
接下的步骤先定义咱们的数据源Module,也就是先定义初始化的地方,以前Person的构造方法是用@Inject。首先命名规则最好加上Module,用@Module标注。而后里面定义个方法,用 @Provides标注。返回值为咱们须要初始化的类,方法名最好是以Provides结尾。其实这里能够定义多个方法,后面说工具
@Module
public class BstudyActivityModule {
@Provides
Human humanProvides(){
return new Human();
}
}
复制代码
而后是咱们的Component。这里与以前不一样的是(modules = BstudyActivityModule.class),这就至关于把注射液放进注射器。这里能够有多个Module,后面说
@Component(modules = BstudyActivityModule.class)
public interface BstudyActivityComponent {
void injectTo(BstudyActivity bstudyActivity);
}
复制代码
Make Project后,在Activity里操做与以前如出一辙。
这个其实不重要,重要的引出4,5的概念。明白这步,后面才好理解。
首先咱们假设2个类,女人类,和灵魂类:且灵魂类有个钱的属性。灵魂类又是女人的属性。灵魂类以下:
public class Soul {
private int money;
public Soul() {
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
复制代码
女人以下:
public class Woman {
private Soul soul;
public Soul getSoul() {
return soul;
}
public Woman(Soul soul) {
this.soul = soul;
}
}
复制代码
首先仍是定义咱们的Module先。既然能够传参,固然是有个money的属性。最终咱们依赖注解是要使用Woman类。咱们的providesWoman方法用@Provides标注,这个时候他回去找Soul的初始化,先经过@Provides去找Soul。这个时候找到了providesSoul。这样就造成了女人类。假如这个时候没有providesSoul。他会去找Soul类里有没有用@Inject标注的构造函数。若是尚未,那么很差意思。出错
@Module
public class CstudyModule {
private int money;
public CstudyModule(int money) {
this.money = money;
}
@Provides
Soul providesSoul() {
Soul soul = new Soul();
soul.setMoney(this.money);
return soul;
}
@Provides
Woman providesWoman(Soul soul) {
return new Woman(soul);
}
}
复制代码
接下来是Component,没有变化
@Component(modules = CstudyModule.class)
public interface CstudyActivityComponent {
void injectTo(CstudyActivity cstudyActivity);
}
复制代码
Activity有些许变化,固然是传参了。咱们给女人的灵魂传了100块,对,女人只值100块!
public class CstudyActivity extends BaseActivity {
@Inject
Woman woman;
@Override
protected void processLogic() {
DaggerCstudyActivityComponent.builder()
.cstudyModule(new CstudyModule(100))
.build().injectTo(this);
}
}
复制代码
咱们把三、经过Module传参apt生成的代码点开DaggerCstudyActivityComponent;看下图是否是发现了一个Builder类,这是apt帮咱们自动生成的,咱们固然也能本身实现
@Component(modules = CstudyModule.class)
public interface DstudyActivityComponent {
void injectTo(DstudyActivity dstudyActivity);
@Component.Builder
interface Builder {
Builder cstudyModule(CstudyModule cstudyModule);
DstudyActivityComponent build();
}
}
复制代码
Activity里使用是同样的。只不过咱们把系统自动帮咱们生成的,本身去写了而已。仍是贴下Activity代码吧
public class DstudyActivity extends BaseActivity {
@Inject
Woman dWoman;
@Override
protected void processLogic() {
DaggerDstudyActivityComponent.builder()
.cstudyModule(new CstudyModule(100))
.build().injectTo(this);
}
}
复制代码
因此@Component.Builder的用法,用module传参的例子。其余都不用变,要变的是Component,定义个Builder并用@Component.Builder标注。这里有2个方法:
这个时候你又说了,传参,咱们老是要new CstudyModule(100)。原本说Dagger2在使用的时候省略new的过程,解耦。但这里还要new,很low是否是。不急不急,强大的google把一切都想好了。这个时候遇到一个新的标注@BindsInstance。
@BindsInstance 大体这里能够理解为帮咱们省去写类的构造方法,而直接去赋值
省掉构造方法,那么固然是首先改咱们的Module。咱们去掉Module的构造方法及money成员变量属性,把money加到providesSoul里成型参。看到这里,这里又可理解为@BindsInstance 其实去找@Provides标记的方法的参数,假如类型一致就去初始化
@Module
public class EstudyModule {
@Provides
Soul providesSoul(int money) {
Soul soul = new Soul();
soul.setMoney(money);
return soul;
}
@Provides
Woman providesWoman(Soul soul) {
return new Woman(soul);
}
}
复制代码
而后是修改的Component,改完Module,固然是modules = EstudyModule.class。这些我就忽略了,看了上面的步骤你也明白,我就直接说关键地方了。用@BindsInstance标注咱们返回值为Builder的方法。里面的参数改为咱们的int Money。固然改为咱们用@Provides标注的类型其实均可以,只不过这里你若是改为Soul soul,固然你初始化仍是要传new Soul。过程就是这个过程
@Component(modules = EstudyModule.class)
public interface EstudyActivityComponent {
void injectTo(EstudyActivity estudyActivity);
@Component.Builder
interface Builder {
@BindsInstance
Builder initMoney(int money);
EstudyActivityComponent build();
}
}
复制代码
最后是咱们的Activity
public class EstudyActivity extends BaseActivity {
@Inject
Woman woman;
@Override
protected void processLogic() {
DaggerEstudyActivityComponent.builder()
.initMoney(100)
.build().injectTo(this);
}
}
复制代码
看到这里,是否是以为Dagger2还比较有意思。更有意思的在后面。固然也愈来愈绕了,可是你得兴奋起来,精髓啊。
这里咱们以Activity和Fragment为例。假设咱们再Activity依赖注入Human类,此时在Fragment里使用
先看定义Module,和以前同样,没什么区别
@Module
public class FstudyActivityModule {
@Provides
Human providesHuman() {
return new Human();
}
}
复制代码
再建ActivityComponent固然这里,你也能够加上void inject(FstudyActivity fstudyActivity)。重要一点是咱们要把依赖注入的类返回出去,定义方法provideHuman,由于是Component依赖Component。因此也能理解
@Component(modules = FstudyActivityModule.class)
public interface FstudyActivityComponent {
Human provideHuman();
}
复制代码
再使用dependencies建FragmentComponent暂且能够理解为子Component,由于后面真的有子Component。dependencies = FstudyActivityComponent.class写上咱们的父Component。后面是注入到Fragment里
@Component(dependencies = FstudyActivityComponent.class)
public interface TestFragmentComponent {
void inject(TestFragment testFragment);
}
复制代码
在Activity里,要先生成ActivityComponent,而后提供个方法,把父Component提供给Fragment
public class FstudyActivity extends BaseActivity {
private FstudyActivityComponent fstudyActivityComponent;
@Override
protected void processLogic() {
fstudyActivityComponent = DaggerFstudyActivityComponent.create();
}
public FstudyActivityComponent getFstudyActivityComponent() {
return fstudyActivityComponent;
}
}
复制代码
在Fragment里
public class TestFragment extends BaseFragment {
@Inject
Human human;
@Override
protected void processLogic(Bundle savedInstanceState) {
FstudyActivityComponent fstudyActivityComponent = ((FstudyActivity) getActivity()).getFstudyActivityComponent();
DaggerTestFragmentComponent.builder()
.fstudyActivityComponent(fstudyActivityComponent)
.build().inject(this);
}
}
复制代码
好了,在fragment可使用human了。在java里使用,确实很绕,代码多的让你难以接受。建议先理解,后面出的一篇在Android中使用,你会很爽。
虽然是实现同一个效果,可是方式不一样,目的是让你更多了解Dagger2。一样以上面的例子。Module和上面同样不变(我这里是为了Demo区域化,虽然类名不一样,可是内容是一致的)
首先建子Component,FragmenComponent,用@Subcomponent标注,并注入咱们的Fragment里。为何先建子Component呢。由于子Component要在父Component返回,绕不绕!!
@Subcomponent
public interface DemoFragmentComponent {
void inject(DemoFragment demoFragment);
}
复制代码
而后是父Component,ActivityComponent,父Component一切正常,返回值是子Component
@Component(modules = GstudyActivityModule.class)
public interface GstudyActivityComponent {
DemoFragmentComponent demoFragmentComponent();
}
复制代码
在Activity里的操做同样,初始化咱们的父Component,并提供方法,返回父Component,供Fragment使用。
而后是Fragment里
public class DemoFragment extends BaseFragment {
@Inject
Human human;
@Override
protected void processLogic(Bundle savedInstanceState) {
GstudyActivityComponent gstudyActivityComponent = ((GstudyActivity) getActivity()).getGstudyActivityComponent();
gstudyActivityComponent
.demoFragmentComponent()
.inject(this);
}
}
复制代码
这样就成功了,能够在Fragment使用human了。看明白了标题6,其实标题7原理是同样的。
效果同样,方式不一样,目的仍是更了解Dagger2。能够看到这里的标注是@Subcomponent.Builder。因此和使用@Subcomponent相似。
好了,仍是以上面的例子为例。这里须要改的是父Component和子Componet。这个时候咱们难免想到@Component.Builder的用法。是否是同样呢。这个时候我只能说相似,可是又不同。毕竟这里多了个sub。咱们先看下@Component.Builder的用法,拷贝以前代码(不知道再去回顾下【标题4】)
@Component(modules = CstudyModule.class。)
public interface DstudyActivityComponent {
void injectTo(DstudyActivity dstudyActivity);
@Component.Builder
interface Builder {
Builder cstudyModule(CstudyModule cstudyModule);
DstudyActivityComponent build();
}
}
复制代码
咱们按照找个方式去写@Subcomponent.Builder。,@Subcomponent.Builder要使用确定是在@Subcomponent下,毋庸置疑。首先发现没有modules = CstudyModule.class。被@Subcomponent取代了。没有Module咱们就使用无参
@Subcomponent
public interface OtherFragmentComponent {
void inject(OtherFragment otherFragment);
@Subcomponent.Builder
interface Builder {
Builder noModule();
OtherFragmentComponent build();
}
}
复制代码
我先告诉告诉你运行结果把,运行结果报错了。
@Subcomponent.Builder types must have exactly one zero-arg method, and that method must return the @Subcomponent type. Already found: hstudyActivityModule()
报错信息以下:意思是不须要Build返回值方法,经过Already found: hstudyActivityModule()知道,已经发现了咱们的Module。咱们再想一想这个标注的名称sub,不就是子Component继承父Componet吗。并且Dagger2内部已经默认了,因此这里没有Builder返回值方法。因此正确的子Component
@Subcomponent
public interface OtherFragmentComponent {
void inject(OtherFragment otherFragment);
@Subcomponent.Builder
interface Builder {
OtherFragmentComponent build();
}
}
复制代码
接下来是父Component,返回值固然是咱们的Builder。
@Component(modules = HstudyActivityModule.class)
public interface HstudyActivityComponent {
OtherFragmentComponent.Builder sonbuilder();
}
复制代码
有人就疑惑了不能够返回子Component吗。咱们假如此时返回子Component,我先告诉你运行报错,信息以下:
Components may not have factory methods for subcomponents that define a builder.
大概意思是:用了@Subcomponent.Builder的话,Component没有工厂模式方法去建立咱们的子Component。好了,就这样,请原谅个人英语四级!!
Activity仍是和以前同样,初始化咱们的父Component,并经过方法返回。Fragment里使用依赖以下
public class OtherFragment extends BaseFragment {
@Inject
Human human;
@Override
protected void processLogic(Bundle savedInstanceState) {
HstudyActivityComponent hstudyActivityComponent = ((HstudyActivity) getActivity()).getHstudyActivityComponent();
hstudyActivityComponent.
sonbuilder().build().inject(this);
}
}
复制代码
好了,绕来绕去,功能实现了!看到这里对Dagger2大体了解了吧。
花了老大劲,别误会,不是要钱。能不能留下个足迹star啊