入门

要实现依赖注入,首先要声明一个依赖对象的需求,这个声明是通过@Inject注解来实现的,所以Car类的实现如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public class Car {

    String mName;

    @Inject
    Engine mEngine;

    public Car(Engine engine){
        mEngine = engine;
    }

    public String getName(){
        return mName;
    }

    Engine getEngine(){
        return mEngine;
    }

}

声明了需求之后,需要声明提供方。提供方声明有两种方式:

  • 使用@Inject注解被依赖对象的构造方法;
  • 使用@Provide注解Module类的普通方法。

先用第一种来实现:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Engine {

    public final int CYLINDER_FUEL_COST = 10;

    int mCylinderNumbers;

    @Inject
    public Engine(){
        mCylinderNumbers = 1;
    }

    public Engine(int cylinderNumbers){
        this.mCylinderNumbers = cylinderNumbers;
    }


    public int getCylinderNumbers(){
        return mCylinderNumbers;
    }


    public void run(Fuel fuel){
        fuel.burn(getCylinderNumbers() * CYLINDER_FUEL_COST);
    }

}

这样就声明了一个完整的依赖关系,但是在Dagger2里,我们声明的依赖关系是无法直接使用的,我们需要使用声明组件(Component)作为依赖关系的容器,Dagger2才会根据组件里要求的依赖关系,帮我们生成对应的Dagger开头的工具类。我们使用@Component来声明一个组件。

1
2
3
4
@Component
public interface EngineComponent {
    Engine getEngine();
}

这里有几个问题:

  • 为什么组件是一个接口,而不是一个类?
  • getEngine方法即不见调用方,也不见提供方,dagger如何绑定需求方和提供方?

这里我们先不做解答,我们先试试效果,构建一下生成DaggerEngineComponent类,并用它为Car类创建Engine对象。

1
2
3
4
5
6
7
8
public class Main {

    public static void main(String[] args){
        Engine engine = DaggerEngineComponent.builder().build().getEngine();
        Car car = new Car(engine);
        System.out.println("cylinderNumbers : " + car.getEngine().getCylinderNumbers());
    }
}

运行一下看到打印:

1
2
cylinderNumbers : 1
Process finished with exit code 0

其实很容易误导我们,以为Dagger2对依赖关系的使用也进行了约束和实现,这是不利于我们清楚地认知dagger2的。在上面的例子中,如果把依赖声明放到Main中,也是可以正常工作的,有兴趣的同学可以自己试验一把。

使用Dagger2实现Engine的注入

注入类型也是依赖关系的一种,也需要Component作为它的容器,才能使用。我们创建一个CarComponent:

1
2
3
4
@Component
public interface CarComponent {
    void inject(Car car);
}

这就声明了注入类型的使用了,Dagger2同样会根据容器的声明为我们生成Dagger2开头的组件。如果你想在EngineComponent里,通过这个方法来声明使用这个注入类型,也是可以的。

1
2
3
4
5
6
7
8
public class Main {

    public static void main(String[] args){
        Car car = new Car(null);
        DaggerCarComponent.builder().build().inject(car);
        System.out.println("cylinderNumbers : " + car.getEngine().getCylinderNumbers());
    }
}

运行结果和上面的调用方式是一样的,这里就不贴了。发现没有,这里我们没有再通过组件创建Engine对象了,很神奇是不是?

是的,如果我们在组件中声明了注入或者需求类型,Dagger2会根据声明的类型自动查找这个类型依赖的所有的其他需求类型,并在注入组件中帮我们一一实现需求的创建(如果需求类型找不到,就会报编译错误),后面我们进行原理分析的时候再进行讲解,这里先记住这点。也正是因为这个自动实现的逻辑,让初学者在dagger2的工作原理的理解上颇费周章,希望这样讲解过后,读者可以理解需求类型和注入类型是相互独立的两个逻辑,是可以灵活使用的。