有什么能比那把黄油刀(butterknife)更加犀利的名字惟有dagger了html
最先的版本Dagger1 由Square公司开发。依赖注入框架主要用于模块间解耦,提升代码的健壮性和可维护性。Dagger 这个库的取名不只仅来自它的本意“匕首”同时也暗示了它的原理java
Dagger2 是一个Android依赖注入框架,由谷歌开发,由于主流是Dagger2因此接下来咱们直接学习如何使用它android
说了那么多,那到底依赖注入是什么呢?上代码:git
public class MainActivity extends AppCompatActivity {
User user;
public void setUser(User user) {
this.user = user;
}复制代码
依赖:MainActivity 包含了一个User对象,咱们就说MainActivity 依赖于user;
注入:由于user对象是经过传递初始的,不是直接new出的对象,因此这样的方式就叫作注入;
经过上面简单的一小段代码估计你们对依赖注入有了了解,经过依赖注入能够有效的减小咱们的耦合,既然这样能够实现依赖注入,为何还须要dagger这样的第三方库处理呢?github
首先new一个实例的过程是一个重复的简单体力劳动,dagger2彻底能够把new一个实例的工做作了,所以咱们把主要精力集中在关键业务上、同时也能增长开发效率上。
省去写单例的方法,而且也不须要担忧本身写的单例方法是否线程安全,本身写的单例是懒汉模式仍是饿汉模式。由于dagger2均可以把这些工做作了。设计模式
每一个app中的ApplicationComponent管理整个app的全局类实例,全部的全局类实例都统一交给ApplicationComponent管理,而且它们的生命周期与app的生命周期同样。
每一个页面对应本身的Component,页面Component管理着本身页面所依赖的全部类实例。
由于Component,Module,整个app的类实例结构变的很清晰。安全
假如不用dagger2的话,一个类的new代码是很是可能充斥在app的多个类中的,假如该类的构造函数发生变化,那这些涉及到的类都得进行修改。设计模式中提倡把容易变化的部分封装起来。app
说了那么多概念,估计你们已经对dagger有了必定的了解,那开我们的使用吧,毕竟实战才是最有用的嘛框架
仍是结合一开始的例子,咱们采用dagger的方式看如何给MainActivity 传递一个依赖的user对象maven
// 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'
}复制代码
@Inject: 一般在须要依赖的地方使用这个注解。换句话说,你用它告诉Dagger这个类或者字段须要依赖注入。这样,Dagger就会构造一个这个类的实例并知足他们的依赖。
@Module: Modules类里面的方法专门提供依赖,因此咱们定义一个类,用 @Module注解,这样Dagger在构造类的实例的时候,就知道从哪里去找到须要的 依赖。modules的一个重要特征是它们设计为分区并组合在一块儿(好比说,在咱们的app中能够有多个组成在一块儿的modules)。
@Provides: 在modules中,咱们定义的方法是用这个注解,以此来告诉Dagger咱们想要构造对象并提供这些依赖。
@Component: Components从根本上来讲就是一个注入器,也能够说是@Inject和@Module的桥梁,它的主要做用就是链接这两个部分。 Components能够提供全部定义了的类型的实例,好比:咱们必须用@Component注解一个接口而后列出全部的 @Modules组成该组件,如 果缺失了任何一块都会在编译的时候报错。全部的组件均可以经过它的modules知道依赖的范围。
@Scope: Scopes但是很是的有用,Dagger2能够经过自定义注解限定注解做用域。后面会演示一个例子,这是一个很是强大的特色,由于就如前面说的同样,不必让每一个对象都去了解如何管理他们的实例
能够粗滤的过一遍,估计看完也是一头雾水,仍是投入到实战中去认识吧!
和传统方法同样很少讲了,设置一些属性罢了
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","XXX@Gmail.com");
}
}复制代码
使用@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一遍