Dagger2相关知识

news2024/11/16 20:26:27

目录

  • 一、Dagger简介
    • 1.1 什么是Dagger?
    • 1.2 Dagger用来干什么?
    • 1.3 使用Dagger2注入对象
    • 1.4 Dagger注解
  • 二、Dagger2使用
    • 2.1 非单例
    • 2.2 局部单例
    • 2.3 全局单例
  • 三、参考链接


一、Dagger简介

1.1 什么是Dagger?

Dagger 2 是一个由 Google 开发的依赖注入框架,用于帮助开发者实现依赖注入(Dependency Injection)的设计模式。依赖注入是一种软件设计模式,用于减少组件之间的耦合,提高代码的可维护性、可测试性和可扩展性。

什么是依赖注入?
维基百科上面的介绍是:在软件工程中,依赖注入是种实现控制反转用于解决依赖性设计模式。一个依赖关系指的是可被利用的一种对象(即服务提供端) 。依赖注入是将所依赖的传递给将使用的从属对象(即客户端)。该服务是将会变成客户端的状态的一部分。 传递服务给客户端,而非允许客户端来建立或寻找服务,是本设计模式的基本要求。

简单来说依赖注入就是将实例对象传入到另一个对象中去。

1.2 Dagger用来干什么?

  • 简化代码:通过依赖注入,Dagger 2 可以帮助开发者管理类之间的依赖关系,避免手动创建和管理对象实例,从而简化代码结构。
  • 提高可测试性:依赖注入可以帮助开发者轻松地替换依赖的对象,从而更容易进行单元测试和集成测试。
  • 解耦合:通过依赖注入,可以将类之间的依赖关系从代码中解耦合,使得代码更加灵活和可维护。
  • 提高可维护性:依赖注入可以帮助开发者更好地组织和管理代码,减少重复代码,使得代码更易于理解和维护。
  • 提高可扩展性:依赖注入可以帮助开发者更容易地扩展和修改代码,使得系统更具弹性和可扩展性。

假如我们的Activity使用Book 实例,且在Activity中使用了成百上千次此实例,此时修改Book()构造器由默认构造器修改为带参的构造器Book(int value),修改Book相关方法,那么Activity里岂不是要修改成百上千次?严重违背了设计模式中的开闭原则,两者之间的耦合度太高,而依赖注入框架Dagger就是能将类之间的依赖关系从代码中解耦合,使得代码更加灵活和可维护。

public class UserActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user);
        Book book=new Book();
    }
    ..........

上述场景在Dagger下使用流程大概如下:
在这里插入图片描述

1.3 使用Dagger2注入对象

Dagger流程就像买快递:用户user购买Book,使用Dagger2实现。
在这里插入图片描述
添加依赖:

    implementation 'com.google.dagger:dagger-android:2.17'
//  implementation 'com.google.dagger:dagger-android-support:2.17' // if you use the support libraries
    implementation 'com.google.dagger:dagger:2.17'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.17'
    annotationProcessor 'com.google.dagger:dagger-android-processor:2.17'

Book类:

public class Book {

    @Inject
    public Book() {

    }

}

包裹:BookModule


@Module      //APT技术,Arouter、DataBinding、Room,基本上都是APT编译器生成代码
public class BookModule {

    @Provides
    public Book GetBook() {
        return new Book();
    }

}

快递员:BookComponent

@Component(modules = BookModule.class)
public interface BookComponent {

    //注入用户收获地址
    void injectUser(UserActivity userActivity);

    @Component.Builder
    interface Builder {
        BookComponent build();
    }
}

用户 UserActivity

public class UserActivity extends AppCompatActivity {

    @Inject
    Book book;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_user);

        DaggerBookComponent.create().injectUser(this);
        Log.d(Tag," --"+book.hashCode());
    }

}

其中DaggerBookComponent需要工程make一下编译产出才能使用,Dagger2较其它依赖注入工具有一个优势,就是它是采用静态编译的方式编译代码的,会在编译期生成好辅助代码,不会影响运行时性能。
在这里插入图片描述

测试一下:Book没有报错,确实已经实例化了。
在这里插入图片描述

1.4 Dagger注解

  • @Component:@Component 是 Dagger 中最重要的注解之一,用于标记一个接口或抽象类作为 Dagger Component。Component 负责连接依赖的提供者(Module)和依赖的消费者(被注入对象)。在 @Component 注解中,通常会指定一个或多个 Module 类,以便 Dagger 可以从这些 Module 中获取依赖的实例。
  • @Component.Builder:@Component.Builder 是用于构建 Dagger Component 实例的接口。通过 Builder 接口,可以定义创建 Component 实例的方法,并在需要时配置 Component。Builder 接口通常用于自定义 Component 的创建过程,例如指定特定的 Module 实例或其他配置。
  • @Module:@Module 是用于提供依赖实例的类的注解。在 Module 类中,通过 @Provides 注解的方法来提供依赖的实例。Module 类的主要作用是告诉 Dagger 如何创建和提供依赖实例,以便在需要时注入到其他类中。
  • @Provides:@Provides 是用于标记 Module 类中提供依赖实例的方法的注解。在 @Provides 注解的方法中,通常会返回一个实例化的对象,并通过方法名指定要提供的依赖类型。Dagger 在需要依赖实例时会调用这些被 @Provides 注解的方法来获取实例。
  • @Inject:@Inject 是用于标记类构造函数、字段或方法的注解,表示这些元素需要依赖注入。当 Dagger 遇到被 @Inject 注解的构造函数时,会尝试实例化该类并满足其依赖。@Inject 还可以用于标记成员变量或方法,指示 Dagger 在创建对象实例时注入这些成员变量或调用这些方法。

通过合理使用这些注解,可以在 Dagger 中实现依赖注入的整个流程,从提供依赖的 Module 到消费依赖的 Component,以及标记需要注入的类和成员。这样可以帮助开发者更好地管理类之间的依赖关系,提高代码的可维护性和可测试性。
通过注解处理器(APT)编译处理注解标识的方法,生成DaggerxxxComponent等文件,进而内部实现注入。


二、Dagger2使用

使用Dagger2依赖注入Coffee----------探索如何实现Coffee全局单例注入的过程

2.1 非单例

依然按照上面的demo,测试一下注入两个类一样的对象,观察哈希值判断是否单例

Coffee

public class Coffee {
    public Coffee() {

    }
}

CoffeeModule

@Module
public class CoffeeModule {
    @Provides
    public Coffee GetCoffee() {
        return new Coffee();
    }
}

CoffeeComponent

@Component(modules = {CoffeeModule.class})
public interface CoffeeComponent {

    void injectActivity_first(Activityfirst activityfirst );

    void injectActivity_second(Activitysecond activitysecond );
}

Activityfirst

public class Activityfirst extends AppCompatActivity implements View.OnClickListener {
    Button button;
    @Inject
    Coffee coffee1;
    @Inject
    Coffee coffee2;

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_activityfirst);
        button = findViewById(R.id.Button_1);
        button.setOnClickListener(this::onClick);

        //方式一
//        DaggerCoffeeComponent.builder()
//                .coffeeModule(new CoffeeModule()).build()
//                .injectActivity_first(this);
//

        //方式二
        DaggerCoffeeComponent.create().injectActivity_first(this);
        Log.d("Henry", " ------" + coffee1.hashCode());
        Log.d("Henry", " ------" + coffee2.hashCode());
    }

    @Override
    public void onClick(View v) {
        startActivity(new Intent(this, Activitysecond.class));
    }

}

测试结果:
在这里插入图片描述
很明显,两个对象哈希值不同,默认不是单例实现。

2.2 局部单例

使用@Singleton注解实现局部单例
Coffee不变

public class Coffee {
    public Coffee() {

    }
}

CoffeeModule 方法添加@Singleton

@Module
public class CoffeeModule {
    @Singleton
    @Provides
    public Coffee GetCoffee() {
        return new Coffee();
    }
}


CoffeeComponent 接口添加@Singleton

@Singleton
@Component(modules = {CoffeeModule.class})
public interface CoffeeComponent {

    void injectActivity_first(Activityfirst activityfirst );

    void injectActivity_second(Activitysecond activitysecond );
}

Activityfirst不变

public class Activityfirst extends AppCompatActivity implements View.OnClickListener {
    Button button;
    @Inject
    Coffee coffee1;
    @Inject
    Coffee coffee2;

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_activityfirst);
        button = findViewById(R.id.Button_1);
        button.setOnClickListener(this::onClick);

        //方式一
//        DaggerCoffeeComponent.builder()
//                .coffeeModule(new CoffeeModule()).build()
//                .injectActivity_first(this);
//

        //方式二
        DaggerCoffeeComponent.create().injectActivity_first(this);
        Log.d("Henry", " ------" + coffee1.hashCode());
        Log.d("Henry", " ------" + coffee2.hashCode());
    }

    @Override
    public void onClick(View v) {
        startActivity(new Intent(this, Activitysecond.class));
    }

}

Activitysecond

public class Activitysecond extends AppCompatActivity {

    @Inject
    Coffee coffee3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_activitysecond);

        //方式一
//        DaggerCoffeeComponent.builder()
//                .coffeeModule(new CoffeeModule()).build()
//                .injectActivity_second(this);
//

        //方式二
        DaggerCoffeeComponent.create().injectActivity_second(this);
        Log.d("Henry", " ------" + coffee3.hashCode());
    }


}

测试结果:同一个Activity下哈希值一致,但是再另一个Activity又重新实例化对象,局部单例。
在这里插入图片描述

2.3 全局单例

如何实现全局单例?局部单例搭配application实现
局部单例代码不变,添加application和修改CoffeeComponent初始化形式
SingletonApplication

public class SingletonApplication extends Application {
    private CoffeeComponent myCoffeeComponent;


    @Override
    public void onCreate() {
        super.onCreate();
        myCoffeeComponent = DaggerCoffeeComponent.builder()
                .coffeeModule(new CoffeeModule())
                .build();
    }

    public CoffeeComponent getMyCoffeeComponent() {
        return myCoffeeComponent;
    }


}

Activityfirst

public class Activityfirst extends AppCompatActivity implements View.OnClickListener {
    Button button;
    @Inject
    Coffee coffee1;
    @Inject
    Coffee coffee2;

    @SuppressLint("MissingInflatedId")
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_activityfirst);
        button = findViewById(R.id.Button_1);
        button.setOnClickListener(this::onClick);
        //方式三

        ((SingletonApplication)getApplication())
                .getMyCoffeeComponent()
                .injectActivity_first(this);

        Log.d("Henry", " ------" + coffee1.hashCode());
        Log.d("Henry", " ------" + coffee2.hashCode());

    }

    @Override
    public void onClick(View v) {
        startActivity(new Intent(this, Activitysecond.class));
    }

}

Activitysecond

public class Activitysecond extends AppCompatActivity {

    @Inject
    Coffee coffee3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_activitysecond);
        
        //方式三
        ((SingletonApplication) getApplication())
                .getMyCoffeeComponent()
                .injectActivity_second(this);

        Log.d("Henry", " ------" + coffee3.hashCode());
    }
}

测试结果:哈希值一致了。
在这里插入图片描述

如果工程很大,需要代码解耦和单例,完全可以使用这种方法满足对应场景。


三、参考链接

Dagger2 For Android最佳实践教程
Dagger 2 使用及原理
Dagger2快速入门和原理解析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1526202.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【论文阅读】MSGNet:学习多变量时间序列预测中的多尺度间序列相关性

MSGNet:学习多变量时间序列预测中的多尺度间序列相关性 文献介绍摘要总体介绍背景及当前面临的问题现有解决方案及其局限性本文的解决方案及其贡献 背景知识的相关工作背景知识问题表述: Method论文主要工作1.输入嵌入和剩余连接 (Input Embedding and R…

git:码云gitee仓库提交以及React项目创建

git:码云gitee仓库提交以及React项目创建 1 前言 先注册准备好码云gitee的账户,并在gitee上新建react仓库并提交代码至远程仓库。 2 操作方式 准备新建React项目并提交到码云gitee上。 (1)进入官网:https://gitee…

Java面试相关问题

一.MySql篇 1优化相关问题 1.1.MySql中如何定位慢查询? 慢查询的概念:在MySQL中,慢查询是指执行时间超过一定阈值的SQL语句。这个阈值是由long_query_time参数设定的,它的默认值是10秒1。也就是说,如果一条SQL语句的执…

【Leetcode-19.删除链表的第N个节点】

题目详情: 给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 示例 1: 输入:head [1,2,3,4,5], n 2 输出:[1,2,3,5]示例 2: 输入:head [1], n 1 输出&#xff1…

什么是Vector Database?

此为看完视频What is a Vector Database?后的笔记。 作者首先对数据库做了分类,其中RTweb表示real time web app。 然后对用例做了分类,最后一个就是适合于AI的近似搜索。 好处,包括灵活性,可扩展性和性价比。 本视频最重要的…

【bioinformation 10】ADMET-CYPs抑制剂预测实战

🌞欢迎来到AI医学的世界 🌈博客主页:卿云阁 💌欢迎关注🎉点赞👍收藏⭐️留言📝 🌟本文由卿云阁原创! 📆首发时间:🌹2024年3月17日&am…

/usr/local/bin/docker-compose: line 1: Not: command not found

安装docker-compose 检查是否安装成功 docker-compose --version 出错 /usr/local/bin/docker-compose: line 1: Not: command not found 检查下载连接是否正确 官网 https://dockerdocs.cn/compose/install/ 根据官网上连接下载 发现下载不了 在版本前加个V 就可以解决 版…

4.1_4 文件的物理结构

文章目录 4.1_4 文件的物理结构(一)文件块、磁盘块(二)文件分配方式——连续分配(三)文件分配方式——链接分配(1)链接分配——隐式链接(2)链接分配——显式链…

JETSON 配置并跑通 NanoDet

JETSON 配置 NanoDet 文章目录 JETSON 配置 NanoDetNanoDet 介绍源码环境搭建及测试配置 NanoDet 的环境环境配置过程中遇到的问题:环境配置完毕验证 NanoDet NanoDet 介绍 可以参考这个博客:NanoDet:这是个小于4M超轻量目标检测模型 源码 …

什么是网站?为什么要搭建网站?

网站:简单来说,网站就是通过互联网来展示信息的页面集合。它可以在电脑或者手机上打开,提供各种功能,比如查看新闻、购买商品、搜索信息等。 一、建网站的目的:展示个人或企业的存在 网站建设的首要目的之一是展示个人…

23-分支和循环语句_习题练习

1、转换以下ASClI码为对应字符并输出他们:73,32,99, 97,110,32,100,111,32,105,116,33 输入:无 输出:一行输出转换题目中给出的所有ASClI码对应的字符,无需以空格隔开。 输入: int main() {int i 0;int arr[] { …

加拿大光量子计算公司Xanadu入局英国多企业量子合作计划

内容来源:量子前哨(ID:Qforepost) 编辑丨慕一 编译/排版丨沛贤 深度好文:1200字丨8分钟阅读 英国航空发动机制造商罗尔斯罗伊斯(Rolls-Royce)、英国量子计算公司Riverlane和加拿大量子计算公…

【Nutx3】middleware目录介绍

简言 记录下nuxt3middleware目录的使用方法。 middleware middleware是存放路由中间件的文件目录。 路由中间件有三种: 匿名(或内联)路由中间件直接在页面中定义。已命名的路由中间件,放在 middleware/ 中,页面使用…

leetcode代码记录(移除元素

目录 1. 题目:2. 我的代码:小结: 1. 题目: 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。 不要使用额外的数组空间,你必须仅使用 O(1)…

Docker入门二(应用部署、迁移与备份、DockerFile、docker私有仓库、Docker-Compose)

文章目录 一、应用部署1.MySQL部署2.Redis部署3.Nginx部署 二、迁移与备份1.容器做成镜像2.镜像备份和恢复(打包成压缩包) 三、DockerFile0.镜像从哪里来?1.什么是DockerFile2.DockerFile 构建特征3.DockerFile命令描述4.构建一个带vim的centos镜像案例5…

网安渗透攻击作业(4)

Unload-labs-01 function checkFile() { var file document.getElementsByName(upload_file)[0].value; if (file null || file "") { alert("请选择要上传的文件!"); return false; } //定义允许上传的文件类型 v…

面渣逆袭:Java基础面试题,46道Java基础八股文(4.8万字,30+手绘图)

1、什么是 Java? Java是一种广泛使用的编程语言,由Sun Microsystems(现为Oracle Corporation的一部分)在1995年首次发布。它是一种面向对象的语言,这意味着它支持通过类和对象的概念来构造程序。 Java设计有一个核心理…

软件工程-第5章 结构化设计

5.1 总体设计的目标及其表示方法 5.2 总体设计 变换设计基本步骤: 第1步:设计准备--复审并精华系统模型; 第2步:确定输入、变换、输出这三部分之间的边界; 第3步:第一级分解--系统模块结构图顶层和第一层…

arcgis数据导出到excel

将arcgis属性数据导出到excel: 1) 工具箱\系统工具箱\Conversion Tools.tbx\Excel\Excel 转表 2)用excel打开导出的图层文件中后缀为.dbf的数据(方便快捷,但是中文易乱码)

GPT-5:人工智能的下一个前沿即将到来

当我们站在人工智能新时代的门槛上时,GPT-5即将到来的呼声愈发高涨且迫切。作为革命性的GPT-3的继任者,GPT-5承诺将在人工智能领域迈出量子跃迁式的进步,其能力可能重新定义我们与技术的互动方式。 通往GPT-5之路 通往GPT-5的旅程已经标记着…