学习Dagger2笔记:【3】@Module & @Provides

本文围绕Dagger依赖注入展开,介绍了使用@Module和@Provides注解生成工厂类的方法,包括无参和含参的@Provides方法。指出这两个注解为生成的工厂类增添了灵活性,可对依赖三方库、系统中的类实现依赖注入,还提及后续将介绍可替代手写注入逻辑的注解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

0. 前言
1. 依赖与注入
2. @Inject
3. @Module & @Provides
4. @Component
5. @Qualifier
6. Provider & Lazy
7. @Scope
8. 注入到Set和Map容器
9. Bind系列注解
10. dagger中依赖关系与继承关系
11. dagger.android

使用@Module和@Provides注解

还记得上一节中添加的需求吗?

要求显示Computer信息前,还要显示当前页面的生成时间

为此,我们对Activity添加了如下成员变量:

@set:Inject lateinit var timestamp: Date

它是一个java.util.Date对象,自然我们是没法将@Inject注解添加到其构造函数上的,因此我们也就没有Date的工厂类,所以之前我们在Bridge中是这样写的:

// 创建依赖
val timestamp = Date(System.currentTimeMillis())
// 使用注入器注入
CaseActivity_MembersInjector.injectSetTimestamp(target, timestamp)

那么有没有办法让dagger生成一个Date的工厂类方便我们调用呢?答案是通过@Module@Provides注解,如下:

@Module // 此注解表明将根据该类中的信息生成一个工厂类,另外该类将作为一个数据仓库类(与MVC、MVP等中的M概念一样)
class TimestampModule { // 通常用@Module注解的类名都以Module结尾
    @Provides // 此注解表明该工厂类和数据仓库会根据被注解的方法生成和提供一个对象实例(回想下之前提到过的Provider接口)
    fun provideTimestamp() = Date(System.currentTimeMillis()) // 通常用@Provides注解的方法名都以provide开头
}

@Module@Provides都是dagger中定义的注解,这里特别说明一下dagger对于@Provides注解的方法默认是不允许返回空的,如果一定要返回空需要用javax.annotation.Nullableandroid.support.annotation.Nullable注解该方法;但kotlin因为天生具有判空语法,只要将方法返回值写清楚(可空或不可空)就可以了

编译一下,果然生成了新的类——TimestampModule_ProvideTimestampFactory,没错,看名字就是我们熟悉的Factory工厂类:

public final class TimestampModule_ProvideTimestampFactory implements Factory<Date> {
  private final TimestampModule module; // 对我们定义的Module的引用

  public TimestampModule_ProvideTimestampFactory(TimestampModule module) {
    this.module = module;
  }

  @Override
  public Date get() {
    return provideTimestamp(module);
  }

  public static TimestampModule_ProvideTimestampFactory create(TimestampModule module) { // 目前此方法不是我们关注的重点
    return new TimestampModule_ProvideTimestampFactory(module);
  }

  public static Date provideTimestamp(TimestampModule instance) {
    return Preconditions.checkNotNull(
        instance.provideTimestamp(), "Cannot return null from a non-@Nullable @Provides method");
  }
}

不过有别于之前@Inject注解在构造函数上生成的工厂,可以看到无论是非静态的get()还是静态的provideTimestamp()工厂方法,其实都是对TimestampModule代理(也许我可以称之为代理工厂)。

有了这个类,我们又可以再次对Bridge类进行修改了

/* CaseActivityBridge.inject()方法 */
// 创建数据仓库
val timestampModule = TimestampModule()
// 创建timestamp依赖
val timestamp = TimestampModule_ProvideTimestampFactory.provideTimestamp(timestampModule)
// 使用注入器注入
CaseActivity_MembersInjector.injectSetTimestamp(target, timestamp)

含参的@Provides方法

之前讲解@Inject注解构造函数时,有区分有参和无参的构造函数,结果发现使用@Inject注解有参的构造函数生成的工厂类比无参构造函数多了:

  • Provider类型的成员变量,其所提供的构造函数所需的参数
  • 非静态的工厂方法get()中使用Provider中提供的数据作为构造函数的参数来产生新的对象实例
  • 静态工厂方法newInstance()参数列表中中多出了构造函数所需要的参数

那么既然@Module+@Provides也是生成工厂类,对于有参的@Provides方法又会是怎样的呢?这里我们假定Memory是一个第三方类,需要我们用@Module+@Provides辅助其生成工厂类:

class Memory(private val size: Int) { // 去掉Memory构造函数上的@Inject注解
    fun execute(builder: StringBuilder) { // Memory执行时返回自身容量信息
        builder.append("Memory Size: ").append(size).append("MB\n")
    }
}

/* 编写MemoryModule类 */
@Module
class MemoryModule {
    @Provides
    fun provideMemory(size: Int) = Memory(size) // 注意这里@Provides注解的方法需要传参
}

编译一下,看下生成的MemoryModule_ProvideMemoryFactory类:

public final class MemoryModule_ProvideMemoryFactory implements Factory<Memory> {
  private final MemoryModule module;

  private final Provider<Integer> sizeProvider; // 与@Inject注解有参构造函数生成的工厂类一样,多出了需要用于参数的Provider

  public MemoryModule_ProvideMemoryFactory(MemoryModule module, Provider<Integer> sizeProvider) {
    this.module = module;
    this.sizeProvider = sizeProvider;
  }

  @Override
  public Memory get() { // 使用Provider中提供的数据作为构造函数的参数来产生新的对象实例
    return provideMemory(module, sizeProvider.get());
  }

  public static MemoryModule_ProvideMemoryFactory create( // 目前此方法不是我们关注的重点
      MemoryModule module, Provider<Integer> sizeProvider) {
    return new MemoryModule_ProvideMemoryFactory(module, sizeProvider);
  }

  public static Memory provideMemory(MemoryModule instance, int size) { // 参数列表中中多出了构造函数所需要的参数
    return Preconditions.checkNotNull(
        instance.provideMemory(size), "Cannot return null from a non-@Nullable @Provides method");
  }
}

可以看到和@Inject一模一样,即工厂类添加Provider类型的成员变量,非静态工厂方法中用Provider提供的数据作为参数,非静态工厂方法中需要传入所需参数,最终还是对MemoryModule的代理

我们再次对Bridge做出改造:

// 创建Memory依赖,注意这里先创建了数据仓库Module,再通过工厂方法创建Memory实例
memory = MemoryModule_ProvideMemoryFactory.provideMemory(MemoryModule(), 8192)

总结

@Module+@Provides为生成的工厂类添加了更多的灵活性,对于依赖于三方库中、系统中等的类,也可以使用工厂方法来实现依赖注入

至此我们要么是手写Injector类,要么是手写Bridge类,其中注入的逻辑虽然抽象层次越来越高,但还是需要我们手写,dagger有没有办法代替我们写这些逻辑呢?答案就是将要介绍的@Component注解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值