什么是Dagger2?
网上有很多包括官网对dagger2 都有非常详细的描述,我也试着说一下自己的理解。
依赖注入:这是看到过最多的解释,啥又是依赖注入呢。简单的说就是赋值,赋值的方式有很多种,比如 构造方法里带参数、setter方法、在声明变量的时候直接 new一个.......,如果在类里面直接赋值就单纯的叫赋值,在其他地方赋值就可以说是依赖注入了。既然有这么多的赋值方法,并且看起来也都挺好用的,那为什么要用Dagger2的依赖注入呢?
为什么要用Dagger2
这就要扯一下设计模式了,相信大家都知道或者听说过工厂模式、工厂方法模式、抽象工厂模式,这类设计模式主要用于创建对象,结偶客户端创建对象的逻辑。例举一个场景:比如一个类A,在其他很多的类当中都被用到了,而且其他的类都是直接用的A的构造方法创建A,当某一天一个特定的需求需要修改A的构造方法(增减里面的参数等),用到的类少点还好说,如果逻辑层级再复杂点,用到的类又很多就.....
回到正题,用官网的话就是
Dagger is a replacement for these FactoryFactory
classes that implements the dependency injection design pattern without the burden of writing the boilerplate. It allows you to focus on the interesting classes. Declare dependencies, specify how to satisfy them, and ship your app.
翻译:
Dagger替代了这些FactoryFactory类,该类实现了依赖注入设计模式,而无需编写样板。它使您可以专注于有趣的课程。声明依赖关系,指定如何满足它们,然后交付您的应用程序。
需要了解的一些前提
想了想还是写一下有必要说明的前提:
- Dagger2不仅仅只是一个程序的框架,他还提供了自动生成代码的工具
- 使用Dagger2(写代码时),你只需要做两件事:
(1)声明依赖关系。
(2)指定如何满足它们。
引入Dagger2
api 'com.google.dagger:dagger:2.26'
annotationProcessor 'com.google.dagger:dagger-compiler:2.26'
如果要用kotlin的话,本片的示例代码MainActivity分部分是kotlin写的
apply plugin: 'kotlin-kapt'
........
........
api 'com.google.dagger:dagger:2.26'
kapt 'com.google.dagger:dagger-compiler:2.26'
开始使用
假如我们要在MainActivity 里面使用一个 Tank 对象;
常规是 new Tank() 完事儿
但是用了Dagger要怎么做呢,为了让读到的人更好理解,我门一步一步加注解,并观察变化,首先看代码:
第一个注解: @Inject 。出现在构造方法 和需要声明对象的地方
Tank类
public class Tank {
@Inject
public Tank() {
}
public void run(){
L.i("Tank is running!");
}
}
MainAcrivity:
class MainActivity : AppCompatActivity() {
@Inject
lateinit var tank : Tank//声明了Tank 与MainActivity的依赖关系
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
就这样,build一下项目
会在build/generated/source/kapt/debug (用了kotlin) 或build/generated/ap_generated_sources/debug(不用kotlin)下生成对应文件
看一下内容
//Tank_Factory当@Inject注解出现在Tank的构造方法里的时候,Dagger就会为我们生成这个类
//但这个类不一定会被用到,当Tank对象过于简单,Dagger 也会在注入的时候直接new
//详细的请看 下面的MainActivity_MembersInjector 类
public final class Tank_Factory implements Factory {
@Override
public Tank get() {//提供Tank的实例
return newInstance();
}
public static Tank_Factory create() {
return InstanceHolder.INSTANCE;
}
public static Tank newInstance() {//静态方法提供实例 简单类的创建时候用到
return new Tank();
}
private static final class InstanceHolder {
private static final Tank_Factory INSTANCE = new Tank_Factory();
}
}
//Ps :这里的Tank_Factory implements Factory
//Factory 的父类 其实是Provider 以后会用到
public interface Factory extends Provider {
}
//MainActivity_MembersInjector 当注解@Inject 出现在声明对象的地方Dagger 就会创建这个类
//注意一下这个类的命名规则,说明只提供MainActivity的各种依赖注入。
public final class MainActivity_MembersInjector implements MembersInjector {
private final Provider tankProvider;//
public MainActivity_MembersInjector(Provider tankProvider) {
this.tankProvider = tankProvider;
}
public static MembersInjector create(Provider tankProvider) {
return new MainActivity_MembersInjector(tankProvider);}
@Override
public void injectMembers(MainActivity instance) {//
injectTank(instance, tankProvider.get());
}
/**
*这个方法是赋值的地方,同样的如果注入的对象很简单会直接用这个方法,而上面的方法就不会调用
*请继续看下面调用的地方
*/
@InjectedFieldSignature("com.example.dagger2test.MainActivity.tank")
public static void injectTank(MainActivity instance, Tank tank) {//真正注入是这句代码
instance.tank = tank;
}
}
这就是第一步:声明了Tank 与MainActivity的依赖关系,而Dagger的插件替我们创建好了这两个类:
那具体调用的代码在哪里呢?
还需要我们做一件事情:
新建一个接口MainComponent 在这里出现了第二我们要知道的注解@Component
@Component//故名思议 部件,就是提供需要注入的这个对象所需要的各种参数,
//Tank类比较简单,所以就只有一个inject(MainActivity activity) 方法就行,
public interface MainComponent {
void inject(MainActivity activity);
}
这时候再次build项目
多了一个DaggerMainComponent的类
直接看代码:
//这个类就是我们依赖注入 直接接触的对象
public final class DaggerMainComponent implements MainComponent {
private DaggerMainComponent() {
}
//默认Builder模式 ,一般是在注入比较复杂
//比如 注入的依赖的对象的构造方法或者成员变量没有注解@Inject,后面写法会用到
//一般用create()获取DaggerMainComponent
public static Builder builder() {
return new Builder();
}
public static MainComponent create() {
return new Builder().build();
}
//开始注入
@Override
public void inject(MainActivity activity) {
injectMainActivity(activity);}
private MainActivity injectMainActivity(MainActivity instance) {
//真正的注入,上面提到过,
//因为Tank类很简单而且没有什么成员变量,就直接new,所以没有用到Factory
MainActivity_MembersInjector.injectTank(instance, new Tank());
return instance;
}
public static final class Builder {
private Builder() {
}
public MainComponent build() {
return new DaggerMainComponent();
}
}
}
接下来在MainActivity里面的代码这样使用:
class MainActivity : AppCompatActivity() {
@Inject
lateinit var tank : Tank
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
DaggerMainComponent.create().inject(this)//注入依赖 这里直接create
tank.run()
}
}
运行一下
I/dagger_tag: Tank is running!
以上只是一个简单的类 注入到Mainactivity, 如果还要注入一个比如说Airplane那只需要
public class Airplane {
@Inject
public Airplane() {
}
public void run(){
L.i("Airplane is flying!");
}
}
class MainActivity : AppCompatActivity() {
...
@Inject
lateinit var airplane: Airplane
...
}
直接运行
I/dagger_tag: Tank is running!
I/dagger_tag: Airplane is flying!
MainActivity_MembersInjector 和 DaggerMainComponent 主要变化:
//MainActivity_MembersInjector:
@InjectedFieldSignature("com.example.dagger2test.MainActivity.airplane")
public static void injectAirplane(MainActivity instance, Airplane airplane) {
instance.airplane = airplane;
}
//DaggerMainComponent
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectTank(instance, new Tank());
MainActivity_MembersInjector.injectAirplane(instance, new Airplane());
return instance;
}
其实还生成了Airplane_Factory 的文件 ,因为上面说的 :类过于简单就没用到。
让需要注入的依赖 对象变得复杂点
Tank 不能自己开需要人去开也就是司机 所以新建一个接口People
public interface People {
public void doSth();
}
再创建一个司机Driver 并 在构造方法上加上注解@Inject
public class Driver implements People{
@Inject//只要有这个注解 就会为你生成 XX_Factory
public Driver() {
}
@Override
public void doSth() {
L.i("driver the tank");
}
}
然后Tank类就变成这样
public class Tank {
@Inject// 只要有这个注解 就会生成和 XX_MembersInjector
Driver driver;//
@Inject
public Tank() {
}
public void run(){
driver.doSth();
L.i("Tank is running!");
}
}
再运行一下
log:
I/dagger_tag: driver the tank
I/dagger_tag: Tank is running!
I/dagger_tag: Airplane is flying!
build 里的目录结构也发生变化:
上面说的类过于简单 就是直接new 这次Tank 多了一成员 Driver 之后会有什么变化呢? 看一下DaggerMainComponent 的 private MainActivity injectMainActivity(MainActivity instance) 方法:
//========DaggerMainComponent
private MainActivity injectMainActivity(MainActivity instance) {
MainActivity_MembersInjector.injectTank(instance, getTank());//这里 不是new 了 变成了getTank()
MainActivity_MembersInjector.injectAirplane(instance, new Airplane());
return instance;
}
//看看getTank()
private Tank getTank() {
return injectTank(Tank_Factory.newInstance());// 这里终于用到了Tank_Factory
}
private Tank injectTank(Tank instance) {
Tank_MembersInjector.injectDriver(instance, new Driver());// 先注入Tank需要的依赖Driver Driver 比较简单 所以 直接new
return instance;
}
//==========DaggerMainComponent end
//=========Tank_Factory
public static Tank newInstance() {
return new Tank();
}
//=========Tank_MembersInjector
//最终Driver 被注入 到Tank中 MainActivity 注入的Tank 也就是这个有Driver 的Tank
@InjectedFieldSignature("com.example.dagger2test.dagger.Tank.driver")
public static void injectDriver(Tank instance, Driver driver) {
instance.driver = driver;
}
@Module 和 @Provides
前面的Driver类的构造方法有@Inject注解 所以Dagger会在DaggerMainComponent 这里称作部件组装管理类,自动提供 Tank对象所需要的Driver,那如果Tank 需要依赖的类的构造方法没有@Inject注解怎么办呢?
这里的场景就是,不是所有的类都是自己写的,总有用到第三方库,我们无法在第三方库的类里的构造方法上加上@Inject 注解。但是Dagger2可以从其他地方去获取实例。这就要用到@Module 和 @Provides这两个注解了。这两个注解其实就是@Component的扩展。XXComponent是用来管理XX里声明的带@Inject的对象需要的“部件”,和组装这些“部件”(生成XX里声明的带@Inject的对象)。这些“部件”的来源除了上面说的构造方法上的@Inject。还有其他来源:
我们往Tank里继续加一个Scout,并且他的构造方法没有注解@Inject
public class Scout implements People{
//去掉注解
// public Scout() {
// }
@Override
public void doSth() {
L.i("Scout start reconnoiter");
}
}
public class Tank {
@Inject
Driver driver;
@Inject//加入新的依赖
People scout; // scout
@Inject
public Tank() {
}
public void run(){
driver.doSth();
L.i("Tank is running!");
scout.doSth();//调用新的依赖的方法
}
}
这时候如果编译的话就会报错了
Scout cannot be provided without an @Inject constructor or an @Provides-annotated method.
public interface MainComponent {
^
.......
意思就是说MainComponent“部件库”里面没有Scout 这个“部件”,要么给Scout的构造方法上加上@Inject注解,要么使用 @Provides提供。
我们已经知道@Inject是干啥的了,现在开始使用@Provides 名字就是提供的意思。需要结合@Module一起使用,@Module 就是指定提供这些“部件的地方”。首先就新建一个Module 类:
@Module//标记
public class MainModule {
@Provides//提供People的实例
People provideScout(){
return new Scout();
}
}
“部件“提供的地方有了,怎么用呢,就需要MainComponent 指定一下到哪里取“部件”
@Component(modules = MainModule.class)//这里指定“部件”获取的地方
public interface MainComponent {
void inject(MainActivity activity);
}
再次运行 一下项目
I/dagger_tag: driver the tank
I/dagger_tag: Tank is running!
I/dagger_tag: Scout start reconnoiter
I/dagger_tag: Airplane is flying!
这里贴一下MainModule_ProvideScoutFactory的代码
//注意这里也是实现了Factory接口 而上面已经介绍了Factory是继承Provider的
public final class MainModule_ProvideScoutFactory implements Factory {
private final MainModule module;
public MainModule_ProvideScoutFactory(MainModule module) {
this.module = module;
}
@Override
public People get() {
return provideScout(module);
}
public static MainModule_ProvideScoutFactory create(MainModule module) {
return new MainModule_ProvideScoutFactory(module);
}
//这里就是提供Scout的地方就是调用了MainModule.provideScout()的方法
public static People provideScout(MainModule instance) {
return Preconditions.checkNotNull(instance.provideScout(), "Cannot return null from a non-@Nullable @Provides method");
}
}
而Tank_Factory的代码也有所改动主要是他的get()的方法实现
//这里的scoutProvider 其实就是MainModule_ProvideScoutFactory了
@Override
public Tank get() {
Tank instance = newInstance();
Tank_MembersInjector.injectDriver(instance, driverProvider.get());
Tank_MembersInjector.injectScout(instance, scoutProvider.get());//加上了Scout的注入
return instance;
}
这里的scoutProvider 其实就是MainModule_ProvideScoutFactory的代码在DaggerMainComponent代码里设置的
//这个方法的实现就是根据注入对象类的复杂程度去调整实现的
private Tank injectTank(Tank instance) {
Tank_MembersInjector.injectDriver(instance, new Driver());
Tank_MembersInjector.injectScout(instance, MainModule_ProvideScoutFactory.provideScout(mainModule));//这里就找到了指定Scout这个“部件提供的地方”
return instance;
}
升级构造方法
使一个类变得复杂呢就是增加他的成员变量和构造方法穿参的数量。这里我们增加了Tank的成员变量。修改Tank的构造方法又会是怎样的情况呢? Tank 需要引擎才能跑起来,建一个Engine类
public class Engine {
@Inject//先使用注入 注解
public Engine(){ }
public void run(){
L.i("provid power");
}
}
public class Tank {
@Inject
Driver driver;
@Inject
People scout;
Engine engine;
@Inject
public Tank(Engine engine) {//构造方法变得复杂了
this.engine = engine;
}
public void run(){
driver.doSth();
engine.run();
L.i("Tank is running!");
scout.doSth();
}
}
运行:
I/dagger_tag: driver the tank
I/dagger_tag: provid power //加入了引擎
I/dagger_tag: Tank is running!
I/dagger_tag: Scout start reconnoiter
I/dagger_tag: Airplane is flying!
可以想象的到Dagger 肯定有去创建了一个Engine_Factory 类,但现在Engine类也不够复杂,所以也用不到这个类,所以直接看一下DaggerMainComponent的方法变动:
private Tank getTank() {
return injectTank(Tank_Factory.newInstance(new Engine()));}//看吧 太简单的就直接new
不过Tank_Factory也随之变动了看newInstance方法:
public static Tank newInstance(Engine engine) {
return new Tank(engine);
}
这就在客户端毫无感知的情况想完成了注入,我们的MainActivity代码还一点未变。
死磕构造方法
那可能你会说可以在Moulde中提供“部件”,那Moulde 也有提供不了的部件的时候怎么办,比如Tank需要回掉侦察的事件给MainActivity。代码:
public interface ViewResult {
public void onView(String result);
}
class MainActivity : AppCompatActivity() ,ViewResult{
......
override fun onView(result: String?) {
L.i(result)
}
}
//Tank 的代码
@Inject
public Tank(Engine engine, ViewResult view) {//
this.engine = engine;
this.view = view;
}
public void run(){
driver.doSth();
engine.run();
L.i("Tank is running!");
scout.doSth();
view.onView("Find the enemy");
}
这下Module 是提供不了了,但Dagger2早已经有对应的方案(真的是专业注入),Component 确是支持扩展的,别忘了他的buid模式是开放出来的我们可以对他进行扩展:修改MainComponent
@Component(modules = MainModule.class)
public interface MainComponent {
void inject(MainActivity activity);
@Component.Builder//标记要对Builder 进行扩展
interface Builder {//
MainComponent build(); //一定要有空参数返回MainComponent 的方法
@BindsInstance//标记这个参数 会被绑定到一个特定健
MainComponent.Builder view(ViewResult view);//每个方法都要返回Builder
}
}
需要改一下MainActivity的方法:
override fun onCreate(savedInstanceState: Bundle?) {
...
DaggerMainComponent
.builder()//以前是create 现在变成build
.view(this)
.build()
...
}
就这样,运行:
I/dagger_tag: driver the tank
I/dagger_tag: provid power
I/dagger_tag: Tank is running!
I/dagger_tag: Scout start reconnoiter
I/dagger_tag: Find the enemy//回掉
I/dagger_tag: Airplane is flying!
再看看DaggerMainComponent的代码
public final class DaggerMainComponent implements MainComponent {
private final ViewResult view;
private final MainModule mainModule;
private DaggerMainComponent(MainModule mainModuleParam, ViewResult viewParam) {
this.view = viewParam;//多一个部件
this.mainModule = mainModuleParam;
}
private Tank getTank() {
return injectTank(Tank_Factory.newInstance(new Engine(), view));}//传如参数加上了新部件view
...
private static final class Builder implements MainComponent.Builder {
private ViewResult view;
@Override
public Builder view(ViewResult view) {//多的部件再这里赋值
this.view = Preconditions.checkNotNull(view);
return this;
}
@Override
public MainComponent build() {
Preconditions.checkBuilderRequirement(view, ViewResult.class);
return new DaggerMainComponent(new MainModule(), view);
}
}
}
这样的话,Dagger的基本使用和简单原理就到这里了,这只是个入门级别的使用,因为其实一个真正Tank 类 肯定是非常的复杂的,肯定还会需要很多的人去驾驶,会装炮弹,里面有通讯系统,通讯系统又由很多设备和人云组成....... ,要把一个类变得复杂,分分钟的事情,但所有组装他的部件都可以交给Dagger的Component去管理。我们只关心声明对象@Inject,管理特殊的组件提供@Module @Provides 就行了。
当然 有时候我们需要用到多个Module 保证能提供到所有的部件:
//
@Component(modules ={ MainModule.class,A.class,B.class...})
public interface MainComponent {
...
}
但有时候,我们在另一个地方比如说MainActivity2 用到 的 部件 包含了MainActivity 需要的
也不用重复去写MainComponent有的东西:
@Component(modules = Main2Module.class , dependencies = MainComponent.class)
public interface Main2Component {
...
}
这些需要自己去探索了,篇幅太长,就到这里