Dagger2相关知识

目录

  • 一、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快速入门和原理解析

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HTML + CSS 核心知识点- 定位

简述: 补充固定定位也会脱离文档流、不会占据原先位置 1、什么是文档流 文档流是指HTML文档中元素排列的规律和顺序。在网页中,元素按照其在HTML文档中出现的顺序依次排列,这种排列方式被称为文档流。文档流决定了元素在页面上的位置和互相之…

【图论】树链剖分

本篇博客参考: 【洛谷日报#17】树链剖分详解Oi Wiki 树链剖分 文章目录 基本概念代码实现常见应用路径维护:求树上两点路径权值和路径维护:改变两点最短路径上的所有点的权值求最近公共祖先 基本概念 首先,树链剖分是什么呢&…

centos7.9的GUI桌面样式不符合默认熟悉的操作习惯

一、问题描述: 原因:桌面样式选错了。 二、解决: 1.先登进去LogOut。 2.点击设置的工具图标中的GNOME Classic即可恢复成默认操作习惯的桌面样式。 3.恢复到默认熟悉的操作界面

基于有限状态机开发健壮的Nodejs/TCP客户端

有限状态机是一种数学计算模型,它描述了在任何给定时间只能处于一种状态的系统的行为。形式上,有限状态机有五个部分: 初始状态值 (initial state)有限的一组状态 (states)有限的一组事件 (events)由事件驱动的一组状态转移关系 (transition…

浏览器如何查看http请求的报文?

HTTP协议用于从WWW服务器传输超文本到本地浏览器的传送协议。 它可以使浏览器更加高效,使网络传输减少。 它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示 (如文本先于图形)等。所以在node.js里…

viple拓展题

数数问题 题目:使用viple来实现程序,使得运行结果能将数字逐个数出即可 思路:首先,数数字,不知道用户具体要求数到多少结束,所以,可以采用简单的对话活动来实现与用户的交互。其次,…

Linux系统安装1Panel管理面板并实现无公网IP远程管理本地服务器

文章目录 前言1. Linux 安装1Panel2. 安装cpolar内网穿透3. 配置1Panel公网访问地址4. 公网远程访问1Panel管理界面5. 固定1Panel公网地址 前言 1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。高效管理,通过 Web 端轻松管理 Linux 服务器,包括主机监控、…

string类型的使用以及编码方式

Redis 中所有的键的类型都是字符串类型,⼀个字符串的最⼤值不能超过 512 MB。 由于 Redis 内部存储字符串完全是按照⼆进制流的形式保存的,所以 Redis 是不处理字符集编码问题的,客⼾端传⼊的命令中使⽤的是什么字符集编码,就存储…

放在你后口袋里的七种基本质量工具

以下是我反复看到的七种质量改进工具。这些质量工具中的大多数已经存在了一段时间,但这肯定不会降低它们的价值! 这些工具最大的优点是使用非常简单,并且可以在中快速使用Minitab统计软件或者从事,但你当然可以使用其他方法&…

【已解决】MySQL:常用的除法运算+精度处理+除数为0处理

目录 问题现象: 问题分析: 拓展: 1、除法运算: 拓展:MySQL中常用的几种除法运算 1、取整除法 2、浮点数除法 3、取余除法 4、向上取整除法 5、向下取整除法 2、运算结果的精度处理 1.1、浮点数 1.2、总位数 1.3、…

c++的const总结(转)

为什么使用const?采用符号常量写出的代码更容易维护;指针常常是边读边移动,而不是边写边移动;许多函数参数是只读不写的。const最常见用途是作为数组的界和switch分情况标号(也可以用枚举符代替),分类如下:…

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

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

十年追光者 | 一段人生故事,聆听《康岛天香》创始人李波的成长历程

​为了响应国家乡村振兴, 绿水青山就是金山银山, 中药材复兴等 国家政策,来自老家河南的李波女士,如今在海南澄迈县桥头镇 开启了她的沉香创业故事, 沉香树一直以来被誉为海南第四颗树, 从最早 20 亩沉香…

java入门 -输入和输出

输入输出 开发中大量会使用输入和输出,今天来总结一下Java语法阶段常使用的输入和输出。 输出 System.out 控制台输出信息。 不换行显示一行: System.out.print( ); System.out.print("hello "); System.out.print("java!");运行结…

JMeter压测SpringBoot项目

压力测试架构图如下: 配置JMeter 在JMeter的bin目录,双击jmeter.bat 新建一个测试计划,并右键添加线程组: 进行配置 一共会发生4万次请求。 ctrl + s保存; 添加http请求: 配置http请求: 配置断言,来判断当前请求是否成功: 正常响应如下:

Tomcat Session ID---会话保持

简单拓补图 一、负载均衡、反向代理 7-1nginx代理服务器配置 [rootdlnginx ~]#yum install epel-release.noarch -y ###安装额外源[rootdlnginx ~]#yum install nginx -y[rootdlnginx ~]#systemctl start nginx.service[rootdlnginx ~]#systemctl status nginx.service [ro…

机器人路径规划:基于Bug算法的机器人路径规划(提供Python代码)

一、Bug算法简介 Bug 算法是一种基于追踪障碍物的路径规划算法,它模拟了一种昆虫寻找巢穴的行为,因此得名Bug算法。Bug算法的基本思路是:当机器人遇到障碍物时,他会沿着障碍物的边缘行走,直到到达目标点。该算法可以分…

如何定期清理数据库中的无效数据?

企业的数据库在运行相当长一段时间后,都会出现无效数据的堆积,这些数据包含了过时、重复、错误、缺失(空字段)的数据,长期占据着宝贵的数据库空间。而在上云热潮的推动下,绝大多数企业已经将他们的业务数据…

Ingress 基于URL路由多个服务

文章目录 前言一、基于请求地址转发不同应用的pod1.创建一个nginx的pod和一个apache的pod及其各自的service2.创建ingress实现一个地址两个path分别访问nginx和apache3.验证根据域名web2.study.com的两个路径/foo和/bar来访问到不同的pod4.分别在nginx和apache的pod里创建网站目…