Dagger2使用


概述

依赖注入(Dependency Injection),简称DI,又叫控制反转(Inversion of Control),简称IOC。Dagger2就是DI框架的一个例子。


作用

将各层的对象以松耦合的方式组织在一起,解耦,各层对象的调用完全面向接口。


提供依赖的两种方式

使用@Inject注解构造器

class Thermosiphon implements Pump {

    @Inject
    Thermosiphon() {
    }
}

使用@Module

@Module
class DripCoffeeModule {
    @Provides static Heater provideHeater() {
        return new ElectricHeater();
    }

    @Provides static Pump providePump(Thermosiphon pump) {
        return pump;
    }
}

使用@Module替代@Inject的情况有:

  • 依赖是一个接口,不能使用构造器。
  • 依赖是第三方类,不能添加@Inject注解。
  • 依赖在使用前需要被配置。

注入依赖的两种方式

使用@Inject和@Provides注解的类对象组成了一个有向图(graph),该图的顶点(vertex)由它们的依赖参数连接。我们可以通过@Component注解的接口来访问这个有向图。我们将Module传递给@Component的modile参数,Dagger2负责生成一个该接口的实现类,事实上构建一个Component的过程就是在构建一个graph。

任何具有默认构造器的Module都不需要显示地设置,builder会自动的创建Module。

CoffeeShop coffeeShop = DaggerCoffeeShop.builder()
                .dripCoffeeModule(new DripCoffeeModule())
                .build();

可简化成:

CoffeeShop coffeeShop = DaggerCoffeeShop.builder().build();

如果所需的依赖不需要构造Module就能提供(@Provides方法是静态的),那么实现类会提供一个create()方法来快速的获取一个Component实例。

CoffeeShop coffeeShop = DaggerCoffeeShop.create();

Component中可以包含两种方法。分别为:

  • Provision Mothod
  • Members-injection Method

Provision Method没有参数并且返回需要的类型。Members-injection Method一般没有返回值,参数是需要注入成员变量的类(一般命名为inject)。


依赖的来源

  • Module中通过@Provides注解的方法;Component通过@Component.modules直接引用,如果Module中通过@Module,include定义了子Module,也一并包括。
  • 使用@Inject注解构造器的类(没有使用@Scope或者@Scope同Component一致)
  • 该Component依赖的Component的Provision Method
  • 该Component本身
  • subComponent的未限定builder
  • 以上依赖的Provider或者Lazy包装类。
  • 以上依赖的Lazy包装类的Provider包装类(如Provider)

单例和作用域

Component只会识别未加作用域或者作用域和自己一致的依赖。所以如果@Provids和可注入类加上了作用域,那么Component一定要加上作用域(和@Provide作用域一致的@Scope进行注解)。

Component的dependencies


Component不仅仅可以有modules也可以有dependencies。也就是依赖其他的Component。

@Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class)
    @PerActivity
    public interface ActivityComponent {
      void inject(MainActivity mainActivity);
    }

注意:只有被依赖的Component中的Provisoin Method才会参与到该Component代表的有向图构建。也就是说只有Provison Method返回的依赖才可以被初始化。


#SubComponent

Component可以依赖其他Component,dependence是实现其方式之一,也可以使用SubComponent。却别在于dependence必须明显的显示依赖关系,而SubComponent不必明确的定义依赖关系。举个例子说明一下:

@Module
public class ModuleA {
    @Provides
    public SomeClassA1 provideSomeClassA1() {
        return new SomeClassA1();
    }
}

@Module
public class ModuleB {
    @Provides
    public SomeClassB1 provideSomeClassB1(SomeClassA1 someClassA1) {
        return new SomeClassB1(someClassA1);
    }
}

public class SomeClassA1 {
    public SomeClassA1() {}
}

public class SomeClassB1 {
    private SomeClassA1 someClassA1;

    public SomeClassB1(SomeClassA1 someClassA1) {
        this.someClassA1 = someClassA1;
    }
}

通过 provideSomeClassB1 可以看出SomeClassB1依赖SomeClassA1

先来看一下用dependence的方式实现

public class ComponentDependency {
    @Component(modules = ModuleA.class)
    public interface ComponentA {
        SomeClassA1 someClassA1();
    }

    @Component(modules = ModuleB.class, dependencies = ComponentA.class)
    public interface ComponentB {
        SomeClassB1 someClassB1();
    }

    public static void main(String[] args) {
        ModuleA moduleA = new ModuleA();
        ComponentA componentA = DaggerComponentDependency_ComponentA.builder()
                .moduleA(moduleA)
                .build();

        ModuleB moduleB = new ModuleB();
        ComponentB componentB = DaggerComponentDependency_ComponentB.builder()
                .moduleB(moduleB)
                .componentA(componentA)
                .build();
    }
}

SomeClassB1依赖SomeClassA1,ComponentB必须明确的定义dependencies,而ComponentA不需要声明ModuleB(modules)。

SubComponent实现方式:

public class SubComponent {
    @Component(modules = {ModuleA.class, ModuleB.class})
    public interface ComponentA {
        ComponentB componentB(ModuleB moduleB);
    }

    @Subcomponent(modules = ModuleB.class)
    public interface ComponentB {
        SomeClassB1 someClassB1();
    }

    public static void main(String[] args) {
        ModuleA moduleA = new ModuleA();
        ModuleB moduleB = new ModuleB();
        ComponentA componentA = DaggerSubComponent_ComponentA.builder()
                .moduleA(moduleA)
                .moduleB(moduleB)
                .build();

        ComponentB componentB = componentA.componentB(moduleB);
    }
}

SomeClassB1依赖SomeClassA1,ComponentB不需要声明依赖,,而ComponentA则需要声明ModuleB(modules),并且ComponentA必须返回@Subcomponent。


#可释放的引用

使用 Scope 注解时,Component 会间接持有绑定的依赖实例的引用,也就是说实例在 Component 还存活时无法被回收。这时可以用@CanReleaseReferences标记 Scope 注解:

@Documented
@Retention(RUNTIME)
@CanReleaseReferences
@Scope
public @interface MyScope {}

然后在 Application 中注入ReleasableReferenceManager对象,在内存不足时调用releaseStrongReferences()方法把 Component 间接持有的强引用变为弱引用。

public class MyApplication extends Application {
    @Inject
    @ForReleasableReferences(MyScope.class)
    ReleasableReferenceManager myScopeReferences;

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        myScopeReferences.releaseStrongReferences();
    }
...
}

这样在内存不足时,DaggerCoffeeShop 间接持有的变 实例为弱引用,如果没有其他对象使用的话就可以被回收。

#Lazy (延迟注入)

有时我们想注入的依赖在使用时再完成初始化,加快加载速度,就可以使用注入Lazy。只有在调用 Lazy 的 get() 方法时才会初始化依赖实例注入依赖。

public class Main {
    @Inject
    Lazy<CoffeeMaker> lazyMaker;

    public void goWork() {
        ...
        lazyMaker.get(); // lazyMaker.get() 返回 CoffeeMaker 实例
        ...
    }
}

#Provider 注入

有时候不仅仅是注入单个实例,我们需要多个实例,这时可以使用注入Provider,每次调用它的 get() 方法都会调用到 @Inject 构造函数创建新实例或者 Module 的 provide 方法返回实例。

public class Main {
    @Inject
    Provider<CoffeeMaker> providerMaker;

    public void goWork() {
        ...
        List<CoffeeMaker> makerList = new ArrayList<CoffeeMaker>(num);
        for (int i = 0; i < num; i ++) {
            makerList.add(providerMaker.get());
        }
        return makerList;

        ...
    }
}

#限定符(Qualifiers)

解决接口或者抽象类不足以描述一个依赖的问题

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface BananaFruit {
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
public @interface AppleFruit {
}

加在所有你想返回确切class的地方。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值