首页 > 其他分享 >这可能是本年度最好用的 Dagger2 使用教程 三(依赖注入器的依赖、子组件、Lazy、Provider)

这可能是本年度最好用的 Dagger2 使用教程 三(依赖注入器的依赖、子组件、Lazy、Provider)

时间:2024-07-16 23:00:49浏览次数:19  
标签:Lazy 依赖 System TaoBao Provider 注入 CPU out

在上一个文章中,我们介绍了 Dagger 中的限定和范围注解,现在我们将视线转移到依赖注入器来,先介绍这个组件的依赖的两种方式,再介绍两个常用的类型。

强烈建议先看完上一个文章:这可能是最详细的 Dagger2 使用教程 二(限定注解 @Named、@Qulifier 和 范围注解 @Singleton、@Scope)

让依赖注入器依赖其他依赖注入器(@Component中的 dependencies 属性)

在实际生活中,一个供应商基本是无法完成所有物品的供应的,但是为了保证商品的尽可能完整,它们可能会依赖其他的供应商。例如在淘宝中,它能供应很多东西,但是有些东西它还是需要找其他供应商的。例如一台电脑中的 CPU,这玩意全球也就两家能生产,所以就是依赖于AMD 和 Intel,有人买的时候,淘宝也是找这两家店拿货。

在本文的例子中,张三从 Taobao 买电脑,其实 CPU 也是要从其他供应商拿的。现在我们就通过这个例子来修改一下我们的代码。

但是在修改之前我们得先思考这样的一个问题,在面向对象的思想中,针对这样的场景,我们往往会抽取父类,使用继承来做,使淘宝这个供应商继承 CPU 供应商,这样淘宝就有了提供 CPU 的能力了。
不过这是在我们普通编程中,在 Dagger 中,就必须使用注入器的依赖,即 @Componentdependencies 属性。我们先将 getCPU 的方法从 Taobao 抽离出来,放到一个 CPUProvider 中:

@Module
public class CPUProvider {

    @Provides
    @Named("AMD")
    public CPU getAMDCPU() {
        return new CPU("AMD");
    }

    @Provides
    @Named("Intel")
    public CPU getIntelCPU() {
        return new CPU("Intel");
    }
}

CPU 供应商能够提供两种类型的 CPU:AMD 的和 Intel 的,但要想从供应商拿货,还需要一个依赖注入器,类似于中通快递。由于 CPU 也就美国这两个公司能生产,那这个专门用于配送 CPU 的注入器我们就叫他 UPS 吧:

@Component(modules = CPUProvider.class)
public interface UPSExpress {
    @Named("AMD") CPU getAMDCPU();
    @Named("Intel") CPU getIntelCPU();
}

注意,对于一般的依赖注入器,我们会定义类似于 injectTo 这样的函数。但是这个依赖注入器是给其他依赖注入器使用的,因此不需要 inject 方法。定义的方法的返回值需要是这个注入器能够提供的类型,否则依赖它的依赖注入器就无法找到这个类型。现在还需要修改一下 ZTOExpress 这个接口,为其添加 dependencies 这个方法:

@SanScope
@Component(modules = {TaoBao.class}, dependencies = UPSExpress.class)
public interface ZTOExpress {
    void deliverTo(Person person);
}

好了,现在咱们就可以使用 ZTOExpressPerson 对象进行依赖注入了。也许你不太懂为什么会有依赖注入器还需要依赖另一个依赖注入器这种情况,可以联想一下跨境电商的配送的过程,一个东西从国外的商店买过来首先要经过国外的快递公司,到了海关,再由国内快递公司接手。这不是就通了。

在进行依赖注入时,还需要修改一点代码:

Person person = new Person("张三");
UPSExpress upsExpress = DaggerUPSExpress.builder().cPUProvider(new CPUProvider()).build();
ZTOExpress ztoExpress = DaggerZTOExpress.builder().taoBao(new TaoBao()).uPSExpress(upsExpress).build();
ztoExpress.deliverTo(person);
person.playGame("赛博朋克2077");

这里创建了 UPSExpress 的实例,并且将其传入到 ZTOExpress 实例中,然后 ZTOExpress 还能够完成注入。

另外,看一看 Dagger 生成的这函数的名字,cPUProvideruPSExpress,真是不忍直视,吐槽一下。最后,看下运行结果:

System.out                I  张三
System.out                I      使用 淘宝的台式机(AMD CPU,希捷 硬盘 @86589c2) 玩     赛博朋克2077
System.out                I      使用 淘宝的笔记本(Intel CPU,希捷 硬盘 @86589c2) 玩     赛博朋克2077

最后提一下,在我们正常的开发过程中,像 UPSExpress 这种其他具体注入器可能会依赖的注入器,一般都会提前在某个地方以单例的方式创建好,当要创建具体注入器时候,再将其设置到具体的注入器中。例如,在 Application 类的 onCreate 方法中创建并提供 get 方法。

使用 @SubComponent 定义子组件、即子依赖注入器

对于上面的场景,中通能够完成对张三的配送,但是在现实生活中,中通这么大的公司,在全国是有很多分部的,真实的配送任务是会被分配给这些地区部门的。一个部门大了,就会有子部门,放到依赖注入器中,如果这个依赖注入器太复杂,那就应该划分为若干个子的依赖注入器,这就要用到 @SubComponent 这个注解了。

我们现在假设张三是住在大上海的,那么为张三进行配送的,肯定是中通的上海分部。咱们就先定义一个中通的上海分部:

@Subcomponent
public interface ZTOShanghaiExpress {
    void deliverTo(Person person);
}

这个上海分部是属于中通的,那么在使用的时候,我们肯定是通过本部才能拿到分部的实例再使用的,也就是说,在 ZTOExpress 中应该有一个返回上海分部的方法:

@SanScope
@Component(modules = {TaoBao.class}, dependencies = UPSExpress.class)
public interface ZTOExpress {
    void deliverTo(Person person);
    ZTOShanghaiExpress getShanghaiDepartment();
}

在使用的时候,我们就通过 getShanghaiDepartment 这个方法返回的 ZTOShanghaiExpress 来进行注入,由于不用总部进行配送,因此 ZTOExpress.deliverTo 这个方法其实是可以删除的。

注入的代码如下:

Person person = new Person("张三");
UPSExpress upsExpress = DaggerUPSExpress.builder().cPUProvider(new CPUProvider()).build();
ZTOExpress ztoExpress = DaggerZTOExpress.builder().taoBao(new TaoBao()).uPSExpress(upsExpress).build();
ZTOShanghaiExpress ztoShanghaiExpress = ztoExpress.getShanghaiDepartment();       //重点
ztoShanghaiExpress.deliverTo(person);
person.playGame("赛博朋克2077");

这里可以看到是通过 ZTOExpressgetShanghaiDepartment 获取到一个 ZTOShanghaiExpress 实例,然后再惊醒注入操作。

这里与 @Component 不同的是,这个 ZTOShanghaiExpress 没有为其设置 modules 属性,也没有设置 @Scope 注解,那它是怎么通过编译的呢?这其实是因为当它属于某个依赖注入器时,会继承其父组件的注解。此处,ZTOShanghaiExpress 就继承了 ZTOExpress@SanScope@Component(modules = {TaoBao.class}, dependencies = UPSExpress.class)

延迟加载 Lazy 和 强制重新加载 Provider

在 Dagger 中, LazyProvider 都是用于包装需要被 Dagger 注入的类型,这就有点像 Java 中的 WeakReference。其中 Lazy 用于延迟加载,所谓的懒加载就是当你需要用到该依赖对象时,Dagger 才帮你去获取一个;Provide 用于强制重新加载,也就是每一要用到依赖对象时,Dagger 都会帮你依赖注入一次。

这里我们修改一下 Person 对象,使其 computerLazy 包装,用到时再初始化;另外再添加一个 cola 的对象,每次用到时,都应该返回一瓶新的可乐:

public class Person {

    @Inject
    @DesktopComputer
    Lazy<Computer> desktop;

    @Inject
    @NotebookComputer
    Lazy<Computer> notebook;

    @Inject
    Provider<Cola> cola;

    public void playGame(String gameName) {
        System.out.print(name + "\n");
        desktop.get().play("\t" + gameName);
        notebook.get().play("\t" + gameName);

        System.out.println("\t 喝了一瓶可乐:"+cola.get());
        System.out.println("\t 再了一瓶可乐:"+cola.get());
        System.out.println("\t 还了一瓶可乐:"+cola.get());
    }
    
    //......
}

然后我们让 TaoBao 这个依赖供应商提供能够提供 Cola,一个普通的 @Provides 方法:

@Module
public class TaoBao {

    @Provides
    public Cola getCola() {
        System.out.println("TaoBao 获取一瓶可乐");
        return new Cola();
    }
    
    //......
}

其他的地方不用更改,我们重新跑一下:

System.out                I  张三
System.out                I  TaoBao 创建台式机
System.out                I  使用 淘宝的台式机(AMD CPU,希捷 硬盘 @bb30609) 玩     赛博朋克2077
System.out                I  TaoBao 创建笔记本
System.out                I  使用 淘宝的笔记本(Intel CPU,希捷 硬盘 @bb30609) 玩     赛博朋克2077
System.out                I  TaoBao 获取一瓶可乐
System.out                I       喝了一瓶可乐:lic.swift.demo.dagger.Cola@b06800e
System.out                I  TaoBao 获取一瓶可乐
System.out                I       再了一瓶可乐:lic.swift.demo.dagger.Cola@59cfa2f
System.out                I  TaoBao 获取一瓶可乐
System.out                I       还了一瓶可乐:lic.swift.demo.dagger.Cola@76b083c

可见 computecola 都是使用时才去调用的,只是 getCola 调用了多次。
如果你使用 Dagger 的话,那么这两个类型肯定会比较常用,不过还好这两个类型都不难,使用过 WeakReference 就知道这两个类型也就是相同的用法。

标签:Lazy,依赖,System,TaoBao,Provider,注入,CPU,out
From: https://blog.csdn.net/Lee_Swifter/article/details/140424167

相关文章

  • 详解Spring循环依赖,以及spring如何通过三级缓存解决循环依赖问题
     首先为了方便理解后面的图解,首先要了解spring的bean的生命周期,下图是sping的bean的生命周期流程图。图解:就是在初始化实例化A时,发现A里面依赖了B,所有看B是否在容器中存在,结果B不存在又去实例化B,B中又依赖与A,但是也不存在,就这样陷入一个死循环就是循环依赖。图解:实......
  • Intel Management Engine WMI Provider 2408.5.4.0 20240221 驱动程序 Intel管理引擎
    驱动程序"IntelManagementEngineWMIProvider2408.5.4.0"是指Intel管理引擎的一部分,它通过Windows管理仪表(WMI)提供对管理引擎功能的访问和管理。这些驱动程序通常用于管理和配置Intel管理引擎的功能,包括安全功能、远程访问以及系统监控等。如果您需要安装或更新这个驱......
  • Conda的冲突解决艺术:在包依赖中寻找和谐
    Conda的冲突解决艺术:在包依赖中寻找和谐在Python开发中,Conda是一个强大的包管理器和环境管理器,它允许用户安装和管理不同版本的包,同时保持环境的隔离。然而,随着项目复杂性的增加,包之间的依赖冲突可能成为开发者面临的棘手问题。本文将深入探讨如何在Conda中使用包依赖冲突......
  • 构建艺术:精通Gradle依赖替换的策略与实践
    构建艺术:精通Gradle依赖替换的策略与实践在软件开发的构建过程中,依赖管理是确保项目顺利进行的关键环节。Gradle,作为一款强大的构建工具,提供了灵活的依赖管理功能,包括依赖替换,这使得开发者能够精细控制项目所依赖的库版本。本文将深入探讨如何在Gradle中配置项目依赖替换,包......
  • Microsoft.Uev.SmbSyncProvider.dll文件丢失导致程序无法运行问题
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个Microsoft.Uev.SmbSyncProvider.dll文件(挑......
  • Spring解决循环依赖问题的四种方法
    Spring解决循环依赖问题的四种方法@Lazy方式使用Setter/FieldInjection使用@PostConstruct实现ApplicationContextAware和InitializingBean不管使用那种方式,最佳的还是通过调整代码结构,从根上设计从而达到避免。定义两个相互依赖的bean(通过构造函数注入)packageicu......
  • 设计模式:使用闭包实现数据集加载过程的依赖倒转
    重点数据集和数据集使用到的参数可以保持不同,将这些不同放到配置文件中进行处理而不是修改获取数据集的加载代码,优点是:减少修改代码的出错统一数据加载的接口格式设计模式:使用闭包实现数据集加载过程的依赖倒转重点前言一、什么是装饰器1、装饰器的定义2、装饰器的使......
  • yarn更新依赖报错:Extracting tar content of undefined failed, the file appears to
    今天从一个git库里更新代码,用yarn安装依赖一直报错。提示如下:Extractingtarcontentofundefinedfailed,thefileappearstobecorrupt,百思不得其解,查了资料说淘宝的镜像源不能用了。用yarninstall--registryhttps://mirrors.huaweicloud.com/repository/npm/,这样解决了......
  • apollo访问阿里云下载YUM的RPM包及其依赖项
     1.确定需要下载的RPM包对于CentOS7,主要需要下载的包包括yum、yum-utils以及它们的依赖。依赖可能包括python-iniparse等。2.使用wget从阿里云镜像下载阿里云的镜像仓库提供了CentOS的软件包,您可以使用以下命令格式从阿里云镜像下载所需的RPM包:1wgethttp://mirrors.al......
  • Android 四大组件 Activity、Service、Broadcast、Content Provider
    一、Android四大组件Activity、Service、Broadcast、ContentProvider1、Activity:1.1、打开App内部Activity:Intentintent=newIntent(SourceActivity.this,TargetActivity.class);startActivity(intent); 1.2、打开Activity并获取返回结果(类似模式对话框): 主Activit......