有什么能比那把黄油刀(butterknife)更加犀利的名字唯有dagger了
最早的版本Dagger1 由Square公司开发。依赖注入框架主要用于模块间解耦,提高代码的健壮性和可维护性。Dagger 这个库的取名不仅仅来自它的本意“匕首”同时也暗示了它的原理
Dagger2 是一个Android依赖注入框架,由谷歌开发,因为主流是Dagger2所以接下来我们直接学习如何使用它
说了那么多,那到底依赖注入是什么呢?上代码:
public class MainActivity extends AppCompatActivity {
User user;
public void setUser(User user) {
this.user = user;
}
依赖:MainActivity 包含了一个User对象,我们就说MainActivity 依赖于user;
注入:因为user对象是通过传递初始的,不是直接new出的对象,所以这样的方式就叫做注入;
通过上面简单的一小段代码估计大家对依赖注入有了了解,通过依赖注入可以有效的减少我们的耦合,既然这样可以实现依赖注入,为什么还需要dagger这样的第三方库处理呢?
1.增加开发效率、省去重复的简单体力劳动
首先new一个实例的过程是一个重复的简单体力劳动,dagger2完全可以把new一个实例的工作做了,因此我们把主要精力集中在关键业务上、同时也能增加开发效率上。
省去写单例的方法,并且也不需要担心自己写的单例方法是否线程安全,自己写的单例是懒汉模式还是饿汉模式。因为dagger2都可以把这些工作做了。
2.更好的管理类实例
每个app中的ApplicationComponent管理整个app的全局类实例,所有的全局类实例都统一交给ApplicationComponent管理,并且它们的生命周期与app的生命周期一样。
每个页面对应自己的Component,页面Component管理着自己页面所依赖的所有类实例。
因为Component,Module,整个app的类实例结构变的很清晰。
3.解耦
假如不用dagger2的话,一个类的new代码是非常可能充斥在app的多个类中的,假如该类的构造函数发生变化,那这些涉及到的类都得进行修改。设计模式中提倡把容易变化的部分封装起来。
说了那么多概念,估计大家已经对dagger有了一定的了解,那开咱们的使用吧,毕竟实战才是最有用的嘛
还是结合一开始的例子,我们采用dagger的方式看如何给MainActivity 传递一个依赖的user对象
Github-地址
// Add plugin https://bitbucket.org/hvisser/android-apt
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
}
}
// Apply plugin
apply plugin: 'com.neenbedankt.android-apt'
// Add Dagger dependencies
dependencies {
compile 'com.google.dagger:dagger:2.x'
apt 'com.google.dagger:dagger-compiler:2.x'
}
可以粗滤的过一遍,估计看完也是一头雾水,还是投入到实战中去认识吧!
和传统方法一样不多讲了,设置一些属性罢了
public class User {
private String name;
private String sex;
private String ads;
******get/set**********
}
module类就是给user初始化并且提供外部调用的类,这里类中我们需要给user初始,并且返回给dagger一个可调用的对象
@Module
public class UserModule {
@Provides
User provideUser(){
return new User("xxxx","SEX","[email protected]");
}
}
使用@Module标识类型为module,并用@Provides标识提供依赖的方法
有了提供依赖的组件(module),我们还需要将依赖注入到需要的对象中。连接提供依赖和消费依赖对象的组件被称为Injector。Dagger2中我们将这个对象其称为component。UserComponent代码如下
@Component(modules = UserModule.class)
public interface UserComponent {
void inject(MainActivity mainActivity);
}
可以看到,Component是一个使用@Component标识的Java interface。interface的inject方法需要一个消耗依赖的类型对象作为参数:通过 @Component 添加了一个 Module : UserModule,此外还有一个inject方法,其中的参数表示要注入的位置(先打个预防针,Component中的方法还可以起到暴露资源,实现Component中的“继承”的作用)
注意:这里必须是真正消耗依赖的类型MainActivity,而不可以写成其父类,比如Activity。因为Dagger2在编译时生成依赖注入的代码,会到inject方法的参数类型中寻找可以注入的对象,但是实际上这些对象存在于MainActivity,而不是Activity中。如果函数声明参数为Activity,Dagger2会认为没有需要注入的对象。当真正在MainActivity中创建Component实例进行注入时,会直接执行按照Activity作为参数生成的inject方法,导致所有注入都失败。(是的,我是掉进这个坑了。)
最后,我们需要在MainActivity中构建Injector对象,通过dagger得到我们的user对象
public class MainActivity extends AppCompatActivity {
@Inject
User user;
UserComponent component;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
component= DaggerUserComponent.builder().userModule(new UserModule()).build();
component.inject(this);
TextView textView=(TextView)findViewById(R.id.tv);
textView.setText("name:"+user.getName()+"\nsex:"+user.getSex()+"\nads:"+user.getAds());
}
}
首先,使用@Inject标志被注入的对象User (注意User 不能为private),之后通过Dagger2生成的实现了我们提供的UserComponent 接口类DaggerUserComponent创建component,调用其inject方法完成注入。
至此,我们使用Dagger实现了最简单的依赖注入!
注意:这里的DaggerUserComponent不是我们自己创建的,是dagger自动在build时(可手动make project)创建的,后边的userModule也是更具你在Component设置的module对象生成的方法-如果不成功需先clean工程在make一遍
源码传送门-csdn-戳我
如果你有任何的问题和建议欢迎加入QQ群告诉我!