前言
dagger2貌似从两年前开始在各大android论坛刷屏,一堆Retrofit+RxJava+Dagger2项目如雨后春笋一样冒了出来。不过当时并没有赶这个潮流,主要是因为手头上项目已经较为庞大,而引入dagger2这种入门门槛比较高的库到项目里收益并不好估计,当然更明显的原因就是懒咯。
那现在为啥要用dagger2呢?因为新公司有一套插件框架,在插件中引入dagger2的成本相对小了不少,可以实验性的去尝试下,但是最终还是决定不在项目中引入dagger2,原因最后一篇文章会说到。
什么是dagger2
关于dagger2的来龙去脉网上的文章说的足够多了,也就不多说了,只提下我觉得重要的几点
- 编译期的依赖注入框架
- 使用代码生成而不用反射
以上两点决定了dagger2的注入只限于编译期可以确定的静态注入,像View,Activity这种运行时产生,且实例是由android框架创建出来的对象只能作为被注入的组件,而无法做为依赖注入到其他地方。当然有舍有得
- dagger2拥有更强的运行时性能
- 较为完善的编译期代码检查
- 因为在编译期就生成了全部代码,所以调试也没什么问题,不过个人觉得生成的代码不够直观,调试起来还是很麻烦
依赖注入框架解决的问题
先说说我理解的依赖
依赖是指某个模块A要实现某个功能需要其他模块B。
最原始也最简单的的方式是在模块内new一个B的对象出来,这样会造成B的构造函数修改,需要修改A中的代码,两者耦合度非常高。
依赖注入
依赖注入是不在A中去创建 B的实例,而是让上层调用者注入一个B的对象,这样可以让模块A不再因为B的构造方法的修改而改变
注意一点,依赖注入只让A摆脱了和B的构造函数的耦合,至于A中对B的依赖基于一个实现还是一个接口,依赖注入是管不着的(依赖注入和面向接口编程都是为了模块间解耦但是没有直接的关系)
如果A依赖于一个接口,而这个接口的实现B又是从外部传入的,这样可以让A完全独立于B而存在,复用起来就更为简单
依赖注入带来的问题
所有的下层模块将创建依赖的任务都往上抛,那么必然会导致最上层的模块需要创建所有必须的依赖,而到依赖的传递过程也会多很多setter或者增加很多构造参数
//网上找的一个比较合适的例子
public class LoginActivity extends AppCompatActivity {
LoginActivityPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
OkHttpClient okHttpClient = new OkHttpClient();
RestAdapter.Builder builder = new RestAdapter.Builder();
builder.setClient(new OkClient(okHttpClient));
RestAdapter restAdapter = builder.build();
ApiService apiService = restAdapter.create(ApiService.class);
UserManager userManager = UserManager.getInstance(apiService);
UserDataStore userDataStore = UserDataStore.getInstance(
getSharedPreferences("prefs", MODE_PRIVATE)
);
//Activity只需要依赖LoginActivityPresenter
//但因为使用了依赖注入,让下层模块相互解耦,导致activity需要承担所有依赖的创建任务
//也就多了上面那么多代码
presenter = new LoginActivityPresenter(this, userManager, userDataStore);
}
}
依赖注入框架的意义
依赖注入框架的目的就在于承担了最上层创建依赖的职责,并且利用注解在合适的地方注入依赖,简化依赖的创建和传递的模板代码
public class LoginActivity extends AppCompatActivity {
@Inject
LoginActivityPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Satisfy all dependencies requested by @Inject annotation
getDependenciesGraph().inject(this);
}
}
当然简化掉的代码没那么夸张,创建依赖的方法只不过是从activity中移到了依赖注入框架中,而依赖注入框架和业务代码之间是没有耦合的,可以按照一定的规则进行复用
dagger2的基本概念
依赖的提供方
dagger2中有两种提供依赖的方式
- 使用@Inject注解构造器的类
- 使用在自己可以修改源码的类中
- 使用@Module注解包含提供依赖方法的类,使用@Provide方法主角提供依赖的方法
- 用在提供没有修改源码权限的类的依赖
依赖的需求方
其实也可以分为两类
- 正常的类,使用了@Inject注解了成员变量的类
- 这里注入依赖需要自己触发
- @Inject注解构造器的类
- 这里@Inject注解的成员变量和构造器参数都会去框架中去找,这个过程是编译时自动完成的
- 这些类既是依赖的需求方也是依赖的提供方
依赖注入器
使用@Component或者@SubComponent注解的接口或者抽象类
- 描述可以提供哪些依赖
- 描述可以注入到哪些依赖需求方
- 管理依赖的生命周期
也许看完上面一堆你还是一头雾水,那么后面就通过代码循序渐进来熟悉dagger2吧
相关文章
dagger2从入门到放弃-概念
dagger2从入门到放弃-最基础的用法介绍
dagger2从入门到放弃-Component的继承体系、局部单例
dagger2从入门到放弃-ActivityMultibindings
dagger2从入门到放弃-dagger.android
dagger2从入门到放弃-其他用法
dagger2从入门到放弃-多模块项目下dagger的使用
dagger2从入门到放弃-为何放弃