ButterKnife和Dagger的简单比较

Android常见的依赖注入框架有:Dagger、Butter Knife、RoboGuice、Android Annotations。
其中用得比较多的是Dagger、Butter Knife。
Dagger是真正的inject,但因为使用dagger实现view injection非常麻烦,所以才会有Butter Knife的诞生。
Butter Knife只是简单是做了绑定View的操作,不是严格意义上的注入,所以称之为View injection。
一句话:ButterKnife是Dagger的补充,ButterKnife只专注于View的注入,其他注入请使用Dagger。

 

依赖注入是一种设计模式

虽然依赖注入早已作为一种设计模式为人所知,依赖注入让开发者的代码低耦合,且能够容易地进行测试。

依赖注入的基础

public class Car {  
 
    private Engine engine;
 
    public Car() {
        engine = new PetrolEngine();
    }
}

这段代码毫无疑问能正常地运作,但我们会发现 Car 类和 Engine 类高度耦合。Car 类一旦被实例化,就会伴随着 Engine 类的实例化,也就使得 Car 类在实例化时必须知道 Engine 类的实例化需要哪些条件,在我们的例子中就是 PetrolEngine 类实例化需要的条件。为了降低耦合,我们可以把代码改成下面这样:

public class Car {  
 
    private Engine engine;
 
    public Car(Engine engine) {
        this.engine = engine;
    }
}

现在我们只需要在实例化 Car 对象的时候传入一个 Engine 对象的引用,这就意味着 Car 类和 Engine 类的耦合度降低了。Car 类不再需要知道 Engine 类的实例化条件是什么,Car 类能调用的任何类型的 Engine 类。

在这个例子中,因为我们通过 Car 类的构造方法,把 Engine 类传递(注入)给 Car 实例,使得我们实现了构造器的注入
其中:engine我们称之为Car对象的“依赖”,传递依赖给Car对象的过程称之为“注入”
依赖注入的思想:将依赖直接传递给类,而不是由类来初始化依赖。
 

如果依赖注入这么简单,为什么需要专门开发一个框架?

还是回到刚刚的例子吧,假设 Engine 类也有它所需要的依赖集,如果我们想为 Engine 类的每一个部件创建类,那么我们很容易就会因此创建几百个类,这些类甚至呈现为一颗复杂的树状图结构的依赖关系。

Android之Dagger2

上面是这种情况的简化图,有图可知,为了得到根对象,我们必须创建叶接对象,并把它们传递给各自的父对象,而且要以正确的顺序去创建,要不然肯定会出现问题。

换句话说,为了创建依赖,我们如履薄冰,一旦顺序搞错了就会代码爆炸。

所以现在你就会发现情况已经变得糟糕起来了,如果我们使用了诸如工厂模式或者建造者模式这样的设计模式去创建我们的类,我们很块就会发现代码变得很复杂、臃肿,充斥着依赖的传递,而且大量的代码都是无意义的、反复的模板代码,这样的代码无疑是开发者不应该写出来的。

从我们的例子里就可以了解到以简单的方式实现依赖注入的坏处在哪里了:复杂的依赖关系、大量的模板代码。也正是如此,依赖注入之前没有流行起来。但不可否认,依赖注入确实是值得使用的,也正因如此,有几个大牛开发了依赖注入框架来解决传统依赖注入用法存在的问题。这些框架大大简化了配置依赖以及生成工厂和建造者对象的过程,是之变得直观和简单。

在 Android 中应该使用什么依赖注入框架呢?

在 Java 中,有着 Spring,Guice 和 Dagger 这些依赖注入框架,那么我们该如何选择呢?

Spring 已经有一段时日了,为了解决声明依赖和初始化对象,Spring 运用了 XML。但这样做有一个问题,就是我们必须写下冗长的 XML 代码来完成这部分工作,而且要在运行时确保它完成了这些工作。所以 Spring 在尝试解决因此衍生的种种问题时也提出了使用依赖注入存在的问题。

Guice 算作对 Spring 的革新。Guice 不需要通过 XML 来配置类的成员域,而是直接通过注解完成了配置的工作,例如 @Inject 和 @Provides。这样看起来依赖注入框架确实要变得更好用了,但 Guice 还是存在一些问题:Debug 和追踪错误有些困难。另外,Guice 使用了大量的反射,虽说对服务器来说这些都不是太大的问题,但在追求用户体验的客户端就会造成很大的开销,影响应用的性能表现从而降低用户体验。

Dagger:虽说 Guice 在依赖注入框架的发展史上踏出了一大步,但它没有解决任何实际的问题,而且它的设计也不是特别适合在移动端开发中使用。因此,Square 开发了 Dagger,造福万千 Android 开发者。

Dagger 这个名字的灵感来源于我们依赖的树状关系,依赖关系呈现的图实际上是有向非循环图(DAG,directed acyclic graph,而在我们的场景中,图呈现上尖下宽的形状,有点像蒙古的圆顶帐篷(ger),所以就叫作 DAGger—— Dagger了。Dagger 的目的是解决将 Guice 应用到移动端存在的问题。

Dagger 将大部分工作负担投到编译时完成而不是运行时,而且尝试尽可能不使用反射,这两部分工作能完成的话就能极大提高依赖注入框架的性能表现。最后 Dagger 完成了这样的工作,但为此也牺牲了一些 Guice 中的特性,但总体来说还是值得的。但 Google 认为这部分工作还能完成地更好,所以他们在尝试开发 Dagger 2。

Dagger 2: 在编译时完成更多的工作,而且将移除反射这部分工作完成地更好,最终完成的 Dagger 2 在 Debug 中的表现也比 Dagger 要好。我真心觉得 Dagger 2 是 Android 中优秀的依赖注入方案了,所以如果你有使用依赖注入框架的话,或者正想要选一个依赖注入框架使用,我认为 Dagger 2 是你的最佳选择。

在 Android 开发中使用

Dagger 2 的首页有丰富的 Dagger 2 的相关概览和特性,这都得感谢 Jake Wharton。上面告诉你要怎么用 Dagger 2 完成依赖注入中的各种工作。下面是一些简单的教程:

Dagger 2 概览

GitHub地址:https://github.com/google/dagger

用户手册:https://google.github.io/dagger/users-guide

Dagger 2 中的域:

http://frogermcs.github.io/dependency-injection-with-dagger-2-custom-scopes/

结合使用Dagger、Espresso 和 Mockito 来完成测试:

http://blog.sqisland.com/2015/04/dagger-2-espresso-2-mockito.html

 

 

 

参考:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2016/0226/3998.html

相关文章: