Dagger2的简单使用及基本原理
前言
java注解除了解耦个人认为还有使代码简洁、逻辑更加突出业务逻辑代码、由于创建对象的集中,更加方便对象的维护与测试、对象的创建和生命周期的管控都交由框架等优点。
Dagger2的历史:
Dagger1是Square公司开发,Dagger2则由谷歌接收在dagger1的分支上开发而来,Dagger1用了反射,消耗了一些性能,Dagger2则被谷歌声称性能提高了13%,但是其灵活性减少
Dagger2的使用
添加依赖:
implementation 'com.google.dagger:dagger:2.4'
annotationProcessor 'com.google.dagger:dagger-compiler:2.4'
创建一个实体类:
public class DaggerTestBean {private String msg="DaggerTestBean注入成功了";@Injectpublic DaggerTestBean(){}public String showMessage(){return msg;}
}
在构造函数上添加@Inject注解
在需要依赖的类中生命对象:
public class DaggerTestActivity extends AppCompatActivity {@InjectDaggerTestBean mDaggerTestBean;private TextView mTvDagger;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_daggertest);mTvDagger = findViewById(R.id.tv_dagger);DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(this);Log.d("daggerTest", "msg: " + mDaggerTestBean.showMessage());}
}
并在声明的对象上添加@Inject注解,仅仅如此还不够
我们需要一个Module,和一个Component类
Module用来声明可以提供哪些实现,如下:
@Module
public class MainModule {}
这里暂时用一个空的添加了@Module注解的Module类
Component是注解器,链接依赖方和Module,如下:
@Singleton
@Component(modules = MainModule.class)
public interface MainComponent {void inject(DaggerTestActivity daggerTestActivity);
}
添加了@Singleton和@Component注解,并指定了modules为MainModule.class,这里是要指明该注入器依赖和被依赖的范围,
需要的模块都建立好了,最后在需要依赖的地方DaggerTestActivity的oncreate中添加注入动作代码:
DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(this);
运行输出:
daggerTest: msg: DaggerTestBean注入成功了
这样简单的使用过程就完成了。
上边的例子是对Bean做了Inject处理,标识可被Module创建对象,也可以在Module中添加提供方法:
@Module
public class MainModule {@ProvidesDaggerTestBean provideTestBean(){return new DaggerTestBean();}
}
这样就不需要在Bean中添加Inject注解了。
Dagger2的原理简单分析
看下编译器做了什么,打开app/build/generated/ap_generated_sources/debug/out/com/modeng/aspro/下多了
DaggerMainComponent.builder().mainModule(new MainModule()).build().inject(this);
追踪inject,发现逻辑还是挺清晰的,
DaggerMainComponent即为编译器自动生成的规则为Dagger+Component类名的类,看下其inject方法:
@Override
public void inject(DaggerTestActivity daggerTestActivity) {daggerTestActivityMembersInjector.injectMembers(daggerTestActivity);
}
调用了daggerTestActivityMembersInjector的injectMenbers方法,看下这个daggerTestActivityMembersInjector对象是什么:
private void initialize(final Builder builder) {this.daggerTestActivityMembersInjector =DaggerTestActivity_MembersInjector.create(com.modeng.voicecontrolpro.utils.DaggerTestBean_Factory.create());
}
在DaggerMainComponent的initialize方法中创建,其就是编译器生成的DaggerTestActivity_MembersInjector类,看下其injectMembers方法:
@Override
public void injectMembers(DaggerTestActivity instance) {if (instance == null) {throw new NullPointerException("Cannot inject members into a null reference");}instance.mDaggerTestBean = mDaggerTestBeanProvider.get();
}
这里有些熟悉的身影了,这里给DaggerTestActivity的mDaggerTestBean赋值了,mDaggerTestBean这个就是咱们添加注解需要注入的对象,继续看下mDaggerTestBeanProvider.get()
public DaggerTestActivity_MembersInjector(Provider<DaggerTestBean> mDaggerTestBeanProvider) {assert mDaggerTestBeanProvider != null;this.mDaggerTestBeanProvider = mDaggerTestBeanProvider;
}
DaggerTestActivity_MembersInjector在创建的时候给mDaggerTestBeanProvider赋值,继续跟踪
public static MembersInjector<DaggerTestActivity> create(Provider<DaggerTestBean> mDaggerTestBeanProvider) {return new DaggerTestActivity_MembersInjector(mDaggerTestBeanProvider);
}
来到了DaggerMainComponent类中:
private void initialize(final Builder builder) {this.daggerTestActivityMembersInjector =DaggerTestActivity_MembersInjector.create(com.modeng.voicecontrolpro.utils.DaggerTestBean_Factory.create());
}
继续看下DaggerTestBean_Factory的create方法,很明显这个是工厂方法:
creat方法拿到的是DaggerTestBean_Factory的实例,通过get方法,拿到创建好的DaggerTestBean对象,至此依赖对象和被依赖对象绑定,完成注入。
public enum DaggerTestBean_Factory implements Factory<DaggerTestBean> {INSTANCE;@Overridepublic DaggerTestBean get() {return new DaggerTestBean();}public static Factory<DaggerTestBean> create() {return INSTANCE;}
}
Dagger2的其它应用
上边讲的是基本用法了,现在来看下其它一些常用切比较复杂的场景:
1. 需要在不同的条件下获取不同的对象,这个时候用到@Named注解:
- 调整下DaggerTestBean:
public class DaggerTestBean {private String msg="DaggerTestBean注入成功了,是测试环境";public DaggerTestBean(){}public DaggerTestBean(String a){this.msg = a;}public String showMessage(){return msg;}
}
- 改变下Module:
@Module
public class MainModule {@Named("debug")@ProvidesDaggerTestBean provideTestBean(){return new DaggerTestBean();}@Named("release")@ProvidesDaggerTestBean provideTestBeanWithParams(){return new DaggerTestBean("DaggerTestBean注入成功了,是生产环境");}
}
- 注入时:
public class DaggerTestActivity extends AppCompatActivity {@Named("params")@InjectDaggerTestBean mDaggerTestBean;
- 输出:daggerTest: msg: DaggerTestBean注入成功了,是生产环境
2. Component依赖
添加一个Module:AMoudle
@Module
public class AModule {@Named("debug")@ProvidesDaggerTestChildBean provideTestBean(){return new DaggerTestChildBean();}@Named("release")@ProvidesDaggerTestChildBean provideTestBeanWithParams(){return new DaggerTestChildBean("DaggerTestChildBean注入成功了,是生产环境");}
}
提供的是DaggerTestChildBean:
public class DaggerTestChildBean {private String msg="DaggerTestChildBean注入成功了,是测试环境";public DaggerTestChildBean(){}public DaggerTestChildBean(String a){this.msg = a;}public String showMessage(){return msg;}
}
当一个Component同时需要MainModule和AModule提供对象时可以有不同的方式:
Comopent注解中添加dependencies参数
@Singleton @Component(modules = AModule.class,dependencies = MainModule.class) public interface MainComponent {void inject(DaggerTestActivity daggerTestActivity); }
Module注解中添加include参数
@Module(includes = AModule.class) public class MainModule {@Named("debug")@ProvidesDaggerTestBean provideTestBean(){return new DaggerTestBean();}@Named("release") @Provides DaggerTestBean provideTestBeanWithParams(){return new DaggerTestBean("DaggerTestBean注入成功了,是生产环境"); }}
Compoent注解中添加Module数组:
@Singleton @Component(modules = {MainModule.class,AModule.class}) public interface MainComponent {void inject(DaggerTestActivity daggerTestActivity); }
3. 当提供的对象是单利的时候,对应的Component也要是单利
这里要注意,单利是跟着被注入的对象的作用域走的,如果如果被注入到Activity中,作用域是Activity,换到其它Activity就重新创建对象了。
@Singleton
@Component(modules = MainModule.class)
public interface MainComponent {void inject(DaggerTestActivity daggerTestActivity);
}
public class DaggerTestActivity extends AppCompatActivity {@Named("release")@InjectDaggerTestBean mDaggerTestBean;@Named("release")@InjectDaggerTestBean mDaggerTestBean1;
Log.d("daggerTest", "msg: mDaggerTestBean的hashCode = " + mDaggerTestBean.hashCode() + " mDaggerTestBean1的hashCode = " + mDaggerTestBean1.hashCode());
输出:daggerTest: msg: mDaggerTestBean的hashCode = 224228315 mDaggerTestBean1的hashCode = 224228315
如果定义在其它Activity:
分别输出:
daggerTest: msg: mDaggerTestBean的hashCode = 224228315 mDaggerTestBean1的hashCode = 224228315
daggerTest: msg: mDaggerTestBean的hashCode = 12558410 mDaggerTestBean1的hashCode = 12558410
4. 实现真正的全局单利
既然单利跟着作用域走,那么在Application中的对象就应该是在整个app生命周期的单例了。
创建自定义Application,并创建MainCompoent对象:
public class MyApplication extends Application {private MainComponent mainComponent;@Overridepublic void onCreate() {super.onCreate();mainComponent = DaggerMainComponent.builder().mainModule(new MainModule()).build();}public MainComponent getMainComponent(){return mainComponent;}}
在Activity中拿到MainComponent对象并注入:
((MyApplication) getApplication()).getMainComponent().inject(this);
public class DaggerTestActivity extends AppCompatActivity {@Named("release")@InjectDaggerTestBean mDaggerTestBean;@Named("release")@InjectDaggerTestBean mDaggerTestBean1;
public class DaggerTest1Activity extends AppCompatActivity {@Named("release")@InjectDaggerTestBean mDaggerTestBean;@Named("release")@InjectDaggerTestBean mDaggerTestBean1;
输出:
singleton: onCreate: mDaggerTestBean = 224228315 mDaggerTestBean1 = 224228315
singleton: onCreate: mDaggerTestBean = 224228315 mDaggerTestBean1 = 224228315
可以看到,两个activity的对象都是一样的。
Dagger2的简单使用及基本原理相关推荐
- Dagger2的简单使用
Dagger2可以更好的帮助我们解耦 不用担心对象或者属性在被生命周期持有导致的未释放 为什么要用Dagger2 举个例子 一般正常调用一个对象的方法是这样 public class A {pu ...
- 编译原理:简单词法分析器的设计与实现
一.实验目的: 设计.编制并调试一个简单的c语言词法分析程序,加深对词法分析原理的理解 二.实验要求: 对单词的构词规则有明确的定义: 编写的分析程序能够正确识别源程序中的单词符号: 识别出的单词以( ...
- 依赖注入神器:Dagger2详解系列
依赖注入神器:Dagger2详解系列 序言 Dagger2是啥 Dagger2是啥,Google告诉我们: Dagger is a fully static, compile-time depende ...
- 关于Dagger2的一些个人理解
写作目的 现在基本上有一些规模的项目,都使用了Dagger2,也不是装13,个人感觉也的确是大势所趋,Dagger2的确有它的优势.借着手上的项目,学习了一下Dagger2,打算用在公司的项目中.今天 ...
- Dagger2的使用以及原理分析
使用 Dagger2的使用说起来并不难,关键在于要掌握Dagger2的提供的几个注解及其意思. 环境搭建 在模块级的build.gradle文件中加入如下依赖: plugins {id 'com.an ...
- HNSW的基本原理及使用
本文首发于:http://xzyin.top/hnsw/ 转载请注明出处:http://xzyin.top/ 相关系列文章可参考: <大规模向量相似度计算(一)--hnswlib的基本使用示例& ...
- 谷歌大脑联手Hinton提出SimCLR新框架,疯狂提升自监督学习性能 | 北邮毕业生一作...
点上方蓝字视学算法获取更多干货 在右上方 ··· 设为星标 ★,与你不见不散 编辑:Sophia 计算机视觉联盟 报道 | 公众号 CVLianMeng 转载于 :新智元 BERT和T5之类的自然 ...
- LDA基本介绍以及LDA源码分析(BLEI)
基本介绍: topic model,主题模型介绍:http://www.cnblogs.com/lixiaolun/p/4455764.html 以及 (http://blog.csdn.net/h ...
- C++中的虚函数(virtual function)
1回顶部 一.简介 虚函数是C++中用于实现多态(polymorphism)的机制.核心理念就是通过基类访问派生类定义的函数.假设我们有下面的类层次: class A { public: virtua ...
- C++中重载与重写函数区别及虚函数(转载)
C++中重载与重写函数区别及虚函数 C++中的虚函数(virtual function) 1.简介 虚函数是C++中用于实现多态(polymorphism)的机制.核心理念就是通过基类访问派生类定义的 ...
最新文章
- C/C++ 知识点---LIB和DLL的区别与使用(网摘)
- UA MATH571B 试验设计VI 随机效应与混合效应1
- 比较两个时间字符串的大小
- 【转】VS.NET2003 调试无法启动
- 二级Python 第三方库
- BugkuCTF-MISC题baby_flag.txt
- 震惊:selenium竟然不是自动化测试工具
- 《编程之美》第2刷勘误
- 四周实现爬虫系统(1)-抓取tripadvisor猫途鹰网站数据信息
- 快门光圈感光度口诀_只要三杯水,就能搞懂光圈/快门/感光度的关系!
- 《早秋客舍》赏析-[唐]杜牧古诗
- 星巴克的员工激励机制
- Java Swing扫雷游戏demo分享
- 登录失败:用户帐户限制。可能的原因包括不允许空密码,登录时间限制,或强制的策略限制。 ...
- ERROR 1819 (HY000): Your password does not satisfy the current policy requirements的解决方法
- 怎样判断驱动程序是否有通过WHQL认证获得微软数字签名
- java eventbus 原理_EventBus的简单使用与原理
- Postman安装(图文)
- Maven中的GroupID和ArtifactID指的是什么?
- 深入理解v4l2buf