Dagger2-终于学会了,还好没放弃(1)
MVP + RxJava + Retrofit + Dagger2 如今已经成了Android开发的主流框架,为了不落伍,我也开始了这个组合框架的学习,力求摆脱之前的那种简单粗暴的分包模式。于是也开始了 Dagger2 的学习之路。这几天断断续续的也看了很多文章,其中当然有很多优秀的文章,但是慢慢的觉得并没有哪一篇文章,是完全的能让人只需要看一篇就能完全让一个人从0开始入门的,Dagger2这个框架学习起来还是比较费劲的,往往是搜了很多文章,综合起来才慢慢的能把很多东西搞懂,这就使得很多人还没入门就多次放弃了(说实话,我也放弃了很多次)。在这里,我想力求做到从一个“白痴”的角度(我是不会承认是我的)进行讲解,以问题为导向来讲解,很多时候我们觉得写博客的人虽然写了很多,觉得很牛逼,但可恨的是,我们还是不懂。其实这并不是我们的错,只是作者忘记了当初自己是怎么过来的,各种问题是怎么一步步被提出来的,结果就是变成了教科书式的讲解。下面就让我们一切从头来过,这一次,决不放弃。 什么是依赖注入,为什么我们需要Dagger2这里,我就不在粘贴那些很官方的描述了,直接大白话。“依赖注入”,从这个词来说,就是 “依赖” 和 “注入” 两个部分嘛。所谓“依赖”,和我们生活中理解的一样,比如说汽车和汽油的关系,汽车只有在有汽油存在的情况下才有意义,严重依赖汽油。而“注入”,很容易让我们想到注射器,将一种液体注入到另一种容器中,这里的“注入”也是一样的,只不过是讲对象绑定到另一个类中而已(简单点来讲就是通过引用进行赋值)。 那为什么需要依赖注入呢?其实就是为了简化无用操作,提高效率,并且对代码进行解耦,使得需求或者一个地方的代码变动,尽可能小的引起其他部分代码的修改。我们以箱子和箱子的水果这个场景为例,进行讲解。 首先创建一个Box类,在其中又依赖了两个类:Apple 和 Banana。 public class Box { Apple mApple; public Box(Apple apple){ mApple = apple; } } 箱子里装有苹果。下面看具体使用: public class MainActivity extends AppCompatActivity { Apple mApple; Box mBox; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mApple = new Apple(); // 先创建 Apple 对象 mBox = new Box(mApple,mBanana); // 将创建好了的 Apple 对象传入 Box 对象的构造函数中 } 可以看到,我们要向得到一个Box对象,必须要先手动生成一个Apple对象和一个Banana对象,试想一下,如果在以后,我们修改了Apple类,在其中添加了对苹果的描述,改变了构造方法,比如变为: public class Apple { public Apple(String desctiption){ Log.i("qc","苹果的描述为: "); } } 那我们就需要再去修改 MainActivity.java 类,显然按,这种编程习惯是不好的。我们能不能通过其他方法,来降低这种影响呢?其实,在编程中我们很多时候是用到过的,只是我们没意识到,想想,在列表加载中,为适配器设置数据、为列表项加载头布局和尾布局的时候你是怎么设置的?Bingo,通过setXXX(...)方法,比如,在Adapter中设置一个public方法来设置数据集: public void setData(List data){ ... } 代码编写的多了,就会更加的接近设计模式、编程思想的本质,毕竟设计模式源于实践并且指导实践的,我们可能再也不愿意去直接在创建Adapter的构造函数中直接传入数据集了。 这里再补充一点,如果你熟悉MVP的话,就很容易能感受到 Dagger2 的魅力,MVP 模式中,View和 Presenter 互相持有对方的引用,而 Presenter 同时又持有 Model 的引用,这样,就造成了View和 Presenter 之间的耦合性比较大,使用 Dagger2 可以减弱这种耦合,直接将 Presenter 通过依赖注入的方式注入到 View 中(例如Activity),当然,如果你还不了解MVP的话,现在学习这篇文章,千万别再跑去看MVP,而丢了主次,完全不需要,那只是 Dagger2 的一个使用场景。 Dagger2学习需要的基础:注解在学习Dagger2之前,你一定要了解的东西就是Java中的注解,可以说如果不懂注解的话,学习Dagger2 是非常痛苦的一件事,甚至完全不知道整个过程是怎么进行的。关于注解,并不难,一两篇文章就可以搞懂,不会花费你很多时间的,可以参考这篇文章:JAVA 注解的几大作用及使用方法详解 以前我们往往是在需要的地方手动的去通过 new 来生成对象,对象的生成和对象的使用是在同一个地方,而 Dagger2 将对象的是生成和其使用分开。说白了,Dagger2 的整个过程就两个:
那么就让我们直接通过具体的例子来进行讲解,让大家更直观的感受到整个过程。 Dagger2 具体使用1.使用Dagger2 需要的相关配置现在Dagger2抛弃了之前采用的apt自动生成代码的方式,而采用annotationProcessor,因而 dependencies { ... ... // Dagger2相关依赖 compile 'com.google.dagger:dagger:2.11-rc2' annotationProcessor 'com.google.dagger:dagger-compiler:2.11-rc2' } 如果用的是比较旧的版本,可以参考GitHub上项目帮助文档:https://bitbucket.org/hvisser... 2.如何生成对象既然是依赖注入,我们首先需要做的就是把对象生产出来。那怎么生成一个对象呢,很容易想到在构造函数前加一个 new ,如:new Apple(),但是既然 Dagger2 能让它自动生成,我们当然不需要自己动手,只需要做某种标记,比如可以直接加上@Inject注解。
3.具体实施步骤这里,我们先针对第一种情况进行讲解,也就是 @Inject 注解,先跑通整个流程 第一步,很简单:就是在Apple类的构造函数上添加 @Inject 注解标记 public class Apple { @Inject // 注意此处的标记是加在构造函数上面的,这个是无参构造函数,有参构造函数的情况下之后会讲 public Apple(){ } public String getDescription(){ return "这个苹果真好吃"; } } 这样,我们就完成了提供者端的操作了,很简单吧,仅仅只是在构造函数上面添加了一个 @Inject 注解。 这一步,是告诉编译器及其他处理程序,我们需要通过此处来生成对象,从而供以后进行依赖注入。 第二步,在目标类中的对应成员变量上也添加相同的注解 @Inject (注意,在目标类中这个注解始终是 @Inject,而不会因为之后使用 @Module 这种方式而改变) public class MainActivity extends AppCompatActivity { @Inject Apple mApple; // 在这里,我们添加了@Inject 注解,告诉处理程序,我们需要将对象注入到此处,给此引用赋值 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } } 在这一步,我们通过在目标类中属性上添加 @Inject 注解,来告诉编译器和其他代码自动生成程序,我们需要将之前生成的对象注入到这里(赋值给这里的引用)。 第三步,通过 @Component 进行牵线搭桥 @Component public interface MainComponent { void inject(MainActivity activity); } 我们在该接口上面添加了 @Component 注解,同时定义了一个抽象方法: 其实,写到这里,我们的整个过程基本上就完成了,下面只需要通过代码,进行实际的注入就好了。可能你会问,这就完成了?我们上面只是定义了一个接口,并没有具体的实现啊,怎么就能注入呢?接下来,我们就来见证奇迹的时刻把,我们把项目编译一下,或者直接点击AS上的绿色的锤子图标:
这就是我们在build.gradley依赖中添加的注解处理器(AnnotationProcess)给我们自动生成的。之前是没有apt这整个目录的,这里面我们可以看到,它也按照我们分的包的结构来生成的,比如“component”包。这里面现在对我们来讲最重要的也是直接跟我们发生关系的就是 public final class DaggerMainComponent implements MainComponent { private MembersInjector<MainActivity> mainActivityMembersInjector; private DaggerMainComponent(Builder builder) { assert builder != null; initialize(builder); } public static Builder builder() { return new Builder(); } public static MainComponent create() { return new Builder().build(); } @SuppressWarnings("unchecked") private void initialize(final Builder builder) { this.mainActivityMembersInjector = MainActivity_MembersInjector.create(Apple_Factory.create()); } // 看到了吧,这个就是我们在之前定义的接口,此处系统自动为我们进行了实现 @Override public void inject(MainActivity activity) { mainActivityMembersInjector.injectMembers(activity); } public static final class Builder { private Builder() {} public MainComponent build() { return new DaggerMainComponent(this); } } } 可以看到,它实现了我们之前写的MainComponent接口,里面也对我们之前定义的抽象方法进行了实现。 @Override public void inject(MainActivity activity) { mainActivityMembersInjector.injectMembers(activity); } 到这里知道为啥我说名字可以随便命名了吧。 好啦,看到这里就够了,千万别陷进去,一会儿我们还会回来继续分析这个类的,千万别觉得我是在浅尝辄止啊。 第四步,也是最后一步,使用 public class MainActivity extends AppCompatActivity { @Inject Apple mApple; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 将依赖注入到该Activity中 DaggerMainComponent .builder() .build() .inject(this); // 打印测试消息 Timber.i(mApple.getDescription()); } } 运行项目,可以看到,在日志中已经打印出来了我们
好了,到这里,我们算是将Dagger2 的一个流程整个跑完了,但这只是一种注入的方式,也就是直接通过在类的构造函数上面添加@Inject注解来完成依赖注入,在下一篇文章中我将会为大家讲解两一种提供对象的方式:@Module (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |