安卓平台上的依赖注入（一）
Java
![](/data/attachment/album/201612/26/204426ezi9djn59j9jiizn.jpg)


刚开始学习软件工程的时候，我们经常会碰到像这样的事情：



> 
> 软件应该符合 SOLID 原则。
> 
> 
> 


但这句话实际是什么意思？让我们看看 SOLID 中每个字母在架构里所代表的重要含义，例如：


* [S - 单职责原则](https://en.wikipedia.org/wiki/Single_responsibility_principle)
* [O - 开闭原则](https://en.wikipedia.org/wiki/Open/closed_principle)
* [L - Liskov 替换原则](http://liskov_substitution_principle/)
* [I - 接口分离原则](https://en.wikipedia.org/wiki/Interface_segregation_principle)
* [D - 依赖反转原则](https://en.wikipedia.org/wiki/Dependency_inversion_principle) 这也是<ruby> 依赖注入 <rp>  （ </rp> <rt>  dependency injection </rt> <rp>  ） </rp></ruby>的核心概念。


简单来说，我们需要提供一个类，这个类有它所需要的所有对象，以便实现其功能。


### 概述


依赖注入听起来像是描述非常复杂的东西的一个术语，但实际上它很简单，看下面这个例子你就明白了：



```
class NoDependencyInjection {
  private Dependency d;

  public NoDependencyInjection() {
    d = new Dependency();
  }
}

class DependencyInjection {
  private Dependency d;

  public DependencyInjection(Dependency d) {
    this.d = d;
  }
}

```

正如我们所见，第一种情况是我们在构造器里创建了依赖对象，但在第二种情况下，它作为参数被传递给构造器，这就是我们所说的<ruby> 依赖注入 <rp>  （ </rp> <rt>  dependency injection </rt> <rp>  ） </rp></ruby>。这样做是为了让我们所写的类不依靠特定依赖关系的实现，却能直接使用它。


参数传递的目标是构造器，我们就称之为构造器依赖注入；或者是某个方法，就称之为方法依赖注入：



```
class Example {
  private ConstructorDependency cd;
  private MethodDependency md;
  Example(ConstructorDependency cd) {
    this.cd = cd; //Constructor Dependency Injection
  }

  public setMethodDependency(MethodDependency md) {
    this.md = md; //Method Dependency Injection
  }
}

```

要是你想总体深入地了解依赖注入，可以看看由 [Dan Lew](https://twitter.com/danlew42) 发表的[精彩的演讲](https://realm.io/news/daniel-lew-dependency-injection-dagger/)，事实上是这个演讲启迪了这篇概述。


在 Android 平台，当需要框架来处理依赖注入这个特殊的问题时，我们有不同的选择，其中最有名的框架就是 [Dagger 2](http://google.github.io/dagger/)。它最开始是由 Square 公司（LCTT 译注：Square 是美国一家移动支付公司）的一些很棒的开发者开发出来的，然后慢慢发展成由 Google 自己开发。首先开发出来的是 Dagger 1，然后 Big G 接手这个项目发布了第二个版本，做了很多改动，比如以<ruby> 注解 <rp>  （ </rp> <rt>  annotation </rt> <rp>  ） </rp></ruby>为基础，在编译的时候完成其任务。


### 导入框架


安装 Dagger 并不难，但需要导入 `android-apt` 插件，通过向项目的根目录下的 `build.gradle` 文件中添加它的依赖关系：



```
buildscript{
  ...
  dependencies{
    ...
    classpath ‘com.neenbedankt.gradle.plugins:android-apt:1.8’
  }
}

```

然后，我们需要将 `android-apt` 插件应用到项目 `build.gradle` 文件，放在文件顶部 Android application 那一句的下一行：



```
apply plugin: ‘com.neenbedankt.android-apt’

```

这个时候，我们只用添加依赖关系，然后就能使用库及其<ruby> 注解 <rp>  （ </rp> <rt>  annotation </rt> <rp>  ） </rp></ruby>了：



```
dependencies{
    ...
    compile ‘com.google.dagger:dagger:2.6’ 
    apt ‘com.google.dagger:dagger-compiler:2.6’
    provided ‘javax.annotation:jsr250-api:1.0’
}

```


> 
> 需要加上最后一个依赖关系是因为 @Generated 注解在 Android 里还不可用，但它是[原生的 Java 注解](https://docs.oracle.com/javase/7/docs/api/javax/annotation/Generated.html)。
> 
> 
> 


### Dagger 模块


要注入依赖，首先需要告诉框架我们能提供什么（比如说上下文）以及特定的对象应该怎样创建。为了完成注入，我们用 `@Module` 注释对一个特殊的类进行了注解（这样 Dagger 就能识别它了），寻找 `@Provide` 注解的方法，生成图表，能够返回我们所请求的对象。


看下面的例子，这里我们创建了一个模块，它会返回给我们 `ConnectivityManager`，所以我们要把 `Context` 对象传给这个模块的构造器。



```
@Module
public class ApplicationModule {
  private final Context context;

  public ApplicationModule(Context context) {
    this.context = context;
  }

  @Provides @Singleton
  public Context providesContext() {
    return context;
  }

  @Provides @Singleton
  public ConnectivityManager providesConnectivityManager(Context context) {
    return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
  }
}

```


> 
> Dagger 中十分有意思的一点是简单地注解一个方法来提供一个单例（Singleton），就能处理所有从 Java 中继承过来的问题。
> 
> 
> 


### 组件


当我们有一个模块的时候，我们需要告诉 Dagger 想把依赖注入到哪里：我们在一个<ruby> 组件 <rp>  （ </rp> <rt>  Component </rt> <rp>  ） </rp></ruby>里完成依赖注入，这是一个我们特别创建的特殊注解接口。我们在这个接口里创造不同的方法，而接口的参数是我们想注入依赖关系的类。


下面给出一个例子并告诉 Dagger 我们想要 `MainActivity` 类能够接受 `ConnectivityManager`（或者在图表里的其它依赖对象）。我们只要做类似以下的事：



```
@Singleton
@Component(modules = {ApplicationModule.class})
public interface ApplicationComponent {

  void inject(MainActivity activity);
}

```


> 
> 正如我们所见，@Component 注解有几个参数，一个是所支持的模块的数组，代表它能提供的依赖。这里既可以是 `Context` 也可以是 `ConnectivityManager`，因为它们在 `ApplicationModule` 类中有声明。
> 
> 
> 


### 用法


这时，我们要做的是尽快创建组件（比如在应用的 `onCreate` 阶段）并返回它，那么类就能用它来注入依赖了：



> 
> 为了让框架自动生成 `DaggerApplicationComponent`，我们需要构建项目以便 Dagger 能够扫描我们的代码，并生成我们需要的部分。
> 
> 
> 


在 `MainActivity` 里，我们要做的两件事是用 `@Inject` 注解符对想要注入的属性进行注解，调用我们在 `ApplicationComponent` 接口中声明的方法（请注意后面一部分会因我们使用的注入类型的不同而变化，但这里简单起见我们不去管它），然后依赖就被注入了，我们就能自由使用他们：



```
public class MainActivity extends AppCompatActivity {
  @Inject
  ConnectivityManager manager;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    ...
    ((App) getApplication()).getComponent().inject(this);
  }
}

```

### 总结


当然了，我们可以手动注入依赖，管理所有不同的对象，但 Dagger 消除了很多比如模板这样的“噪声”，给我们提供有用的附加品（比如 `Singleton`），而仅用 Java 处理将会很糟糕。




---


via: <https://medium.com/di-101/di-101-part-1-81896c2858a0#.3hg0jj14o>


作者:[Roberto Orgiu](https://medium.com/@_tiwiz) 译者:[GitFuture](https://github.com/GitFuture) 校对:[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出


OK
# DI 101 — Part 1

## Dependency Injection for the Android platform

When we first start studying software engineering, we usually bump into something like:

Software shall be SOLID.


but what does that mean, in fact? Well, let’s just say that **each character of the acronym means something really important for the architecture**, such as:

**S**ingle Responsibility Principle**O**pen/closed principle**L**iskov substitution principle**I**nterface segregation principlewhich is the core concept on which the dependency injection is based.**D**ependency inversion principle

Simply, *we need to provide a class with all the objects it needs in order to perform its duties*.

## Overview

Dependency Injection sounds like a very complex term for something that is, in fact, really easy and could be explained with this example:

As we can see, in the first case, we create the dependency in the constructor, while in the second case it gets passed as a parameter. The second case is what we call *dependency injection*. We do this so that our class does not depend on the specific implementation of its dependency but it just uses it.

Moreover, based on whether the parameter is passed over to the constructor or to a method, we talk either about constructor dependency injection or method dependency injection:

If you want to know more about Dependency Injection in general, be sure to check out [this amazing talk](https://realm.io/news/daniel-lew-dependency-injection-dagger/) from [Dan Lew](https://twitter.com/danlew42) that actually inspired this overview.

On Android, we have different choices when it comes to frameworks for solving this particular problem but the most famous is [Dagger](http://google.github.io/dagger/) 2, first made by the awesome guys at Square and then evolved by Google itself. Specifically, Dagger 1 was made by the first and then Big G took over the project and created the second version, with major changes such being based on annotations and doing its job at compile time.

## Importing the framework

Setting up Dagger is no big deal, but it requires us to import the **android-apt** plugin by adding its dependency in the *build.gradle* file in the root directory of the project:

`buildscript{`

...

dependencies{

...

classpath ‘com.neenbedankt.gradle.plugins:android-apt:1.8’

}

}

Then, we need to apply the **android-apt** plugin in the top part of the app’s *build.gradle* file, right below the Android application one:

`apply plugin: ‘com.neenbedankt.android-apt’`

At this point, we just need to add the dependencies so that we are now able to use the libraries and its annotations:

`dependencies{`

...

compile ‘com.google.dagger:dagger:2.6’

apt ‘com.google.dagger:dagger-compiler:2.6’

provided ‘javax.annotation:jsr250-api:1.0’

}

The last dependency is needed because the

@Generatedannotation is not yet available on Android, but[it’s pure Java].

## Dagger Modules

For injecting our dependencies, we first need to tell the framework what we can provide (i.e. the Context) and how that specific object is built. In order to do this, we annotate a specific class with the **@Module** annotation (so that Dagger is able to pick it up) scan for the **@Provide** annotated methods and generate the graph that will give us the object we request.

Let’s see an example where we create a module that will give us the **ConnectivityManager.** So we need the **Context** that we will pass in the constructor of the module:

A very interesting feature of Dagger is providing a Singleton by simply annotating a method, dealing with all the issues inherited from Java by itself.


## The Components

Once we have a module, we need to tell Dagger where we want our dependencies to be injected: we do this in a Component, *a specifically annotated interface* in which we create different methods, where the parameters are the classes into which we want our dependencies to be injected.

Let’s give an example and say that we want our **MainActivity** class to be able to receive the **ConnectivityManager **(or any other dependency in the graph). We would simply do something like this:

As we can see, the @Component annotation takes some parameters, one being an array of the modules supported, meaning the dependencies it can provide. In our case, that would be both the Context and the ConnectivityManager, as they are declared in the ApplicationModule class.


## Wiring up

At this point, what we need to do is create the Component as soon as possible (such as in the onCreate phase of the Application) and return it, so that the classes can use it for injecting the dependencies:

In order to have the DaggerApplicationComponent automatically generated by the framework, we need to build our projects so that Dagger can scan our codebase and generate the parts we need.


In our **MainActivity**, though, the two things we need to do are annotate a property we want to inject with the **@Inject **annotation and invoke the method we declared in the **ApplicationComponent** interface (note that this last part varies based on what kind of injection we are performing, but for the moment we can leave it as is for the simplicity), so that our dependencies get injected and we can use them freely:

## Conclusion

Of course, we could do Dependency Injection manually, managing all the different objects, but Dagger takes away a lot of the “noise” involved with such boilerplate, giving us some nice additions (such as **Singleton**) that would otherwise be pretty awful to deal with in Java.