Dagger2相关知识

2024-03-19 13:12
文章标签 知识 相关 dagger2

本文主要是介绍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 {@Overrideprotected 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 librariesimplementation '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 {@Injectpublic Book() {}}

包裹:BookModule


@Module      //APT技术,Arouter、DataBinding、Room,基本上都是APT编译器生成代码
public class BookModule {@Providespublic Book GetBook() {return new Book();}}

快递员:BookComponent

@Component(modules = BookModule.class)
public interface BookComponent {//注入用户收获地址void injectUser(UserActivity userActivity);@Component.Builderinterface Builder {BookComponent build();}
}

用户 UserActivity

public class UserActivity extends AppCompatActivity {@InjectBook book;@Overrideprotected 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 {@Providespublic 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;@InjectCoffee coffee1;@InjectCoffee coffee2;@SuppressLint("MissingInflatedId")@Overrideprotected 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());}@Overridepublic 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@Providespublic 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;@InjectCoffee coffee1;@InjectCoffee coffee2;@SuppressLint("MissingInflatedId")@Overrideprotected 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());}@Overridepublic void onClick(View v) {startActivity(new Intent(this, Activitysecond.class));}}

Activitysecond

public class Activitysecond extends AppCompatActivity {@InjectCoffee coffee3;@Overrideprotected 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;@Overridepublic 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;@InjectCoffee coffee1;@InjectCoffee coffee2;@SuppressLint("MissingInflatedId")@Overrideprotected 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());}@Overridepublic void onClick(View v) {startActivity(new Intent(this, Activitysecond.class));}}

Activitysecond

public class Activitysecond extends AppCompatActivity {@InjectCoffee coffee3;@Overrideprotected 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快速入门和原理解析

这篇关于Dagger2相关知识的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/826108

相关文章

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

sqlite3 相关知识

WAL 模式 VS 回滚模式 特性WAL 模式回滚模式(Rollback Journal)定义使用写前日志来记录变更。使用回滚日志来记录事务的所有修改。特点更高的并发性和性能;支持多读者和单写者。支持安全的事务回滚,但并发性较低。性能写入性能更好,尤其是读多写少的场景。写操作会造成较大的性能开销,尤其是在事务开始时。写入流程数据首先写入 WAL 文件,然后才从 WAL 刷新到主数据库。数据在开始

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容

1.访问位与修改位的题型(淘汰哪一页) 访问位:为1时表示在内存期间被访问过,为0时表示未被访问;修改位:为1时表示该页面自从被装入内存后被修改过,为0时表示未修改过。 置换页面时,最先置换访问位和修改位为00的,其次是01(没被访问但被修改过)的,之后是10(被访问了但没被修改过),最后是11。 2.内聚的类型 功能内聚:完成一个单一功能,各个部分协同工作,缺一不可。 顺序内聚:

log4j2相关配置说明以及${sys:catalina.home}应用

${sys:catalina.home} 等价于 System.getProperty("catalina.home") 就是Tomcat的根目录:  C:\apache-tomcat-7.0.77 <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c{1}:%L - %msg%n" /> 2017-08-10

Node Linux相关安装

下载经编译好的文件cd /optwget https://nodejs.org/dist/v10.15.3/node-v10.15.3-linux-x64.tar.gztar -xvf node-v10.15.3-linux-x64.tar.gzln -s /opt/node-v10.15.3-linux-x64/bin/npm /usr/local/bin/ln -s /opt/nod

git ssh key相关

step1、进入.ssh文件夹   (windows下 下载git客户端)   cd ~/.ssh(windows mkdir ~/.ssh) step2、配置name和email git config --global user.name "你的名称"git config --global user.email "你的邮箱" step3、生成key ssh-keygen

zookeeper相关面试题

zk的数据同步原理?zk的集群会出现脑裂的问题吗?zk的watch机制实现原理?zk是如何保证一致性的?zk的快速选举leader原理?zk的典型应用场景zk中一个客户端修改了数据之后,其他客户端能够马上获取到最新的数据吗?zk对事物的支持? 1. zk的数据同步原理? zk的数据同步过程中,通过以下三个参数来选择对应的数据同步方式 peerLastZxid:Learner服务器(Follo

rtmp流媒体编程相关整理2013(crtmpserver,rtmpdump,x264,faac)

转自:http://blog.163.com/zhujiatc@126/blog/static/1834638201392335213119/ 相关资料在线版(不定时更新,其实也不会很多,也许一两个月也不会改) http://www.zhujiatc.esy.es/crtmpserver/index.htm 去年在这进行rtmp相关整理,其实内容早有了,只是整理一下看着方

枚举相关知识点

1.是用户定义的数据类型,为一组相关的常量赋予有意义的名字。 2.enum常量本身带有类型信息,即Weekday.SUN类型是Weekday,编译器会自动检查出类型错误,在编译期间可检查错误。 3.enum定义的枚举类有什么特点。         a.定义的enum类型总是继承自java.lang.Enum,且不能被继承,因为enum被编译器编译为final修饰的类。         b.只能定义