依赖注入这个模式(模式已经用烂了,这里再烂一次)是用来给应用的各部分解耦的。使应用开发更加可扩展,更容易维护。经过本文你会学到如何使用Dagger2来处理依赖。java
若是以对象须要另外的一个对象才能完成一个完整功能的话,那么这里就存在一个依赖。好比,悟空要用金箍棒才能三打白骨精,要筋斗云才能十万八千里。悟空有对金箍棒和筋斗云的依赖。你能够在悟空对象里初始化金箍棒,也能够用一个工厂方法批量生产金箍棒。使用依赖注入能够无需一个专门的类来初始化这些依赖对象。这样就实现了解耦。android
本教程会使用最新的Dagger2(当前的版本是2.2)。这里是官网。你能够在这里找到最新的发布。git
Android Studio是必须的。其余:github
注解讲解:后端
@Module
这个annotation修饰的类专门用来提供依赖@Provides
这个annotation修饰的方法用在Module
类里@Inject
用来annotation一个依赖(能够是构造方法、field或者通常的方法)@Component
链接@Module
和注入的桥梁这些名词看起来很是抽象。下面稍微解释一下。依赖反射并无什么神奇的地方。只不过是咱们须要单独写初始化依赖的地方由其余的框架代替了。这个依赖关系也有咱们常写的代码转移到了“配置文件”中。api
在好久之前,依赖注入的框架就是这样处理依赖注入的:读取配置文件的依赖关系,而后用反射的方法初始化被依赖对象并赋值给调用依赖的对象。好比,咱们以前在悟空类中初始化金箍棒:android-studio
public class Wukong { private Jingubang jingubang; public Wukong(){ // 依赖 this.jingubang = Jingubang(); } }
后来有了使用配置文件的依赖注入(这里都是虚构的文件格式):app
<xml> <com.xiyou.Wukong> <dependency field="jingubang"> <com.xiyou.Jingubang /> </dependency> </com.xiyou.Wukong> </xml>
在悟空使用金箍棒的时候,依赖注入框架自动初始化好了金箍棒,并赋值给了悟空。框架
如今使用Dagger2。这里就有不得不说的牛X的地方了。由于是在Android里能用的资源没有后端那么多。尤为反射消耗比较大!因此Dagger为了知足移动开发节约资源的须要,没有使用反射实现依赖注入。而是在编译的时候同时生成依赖注入的相关代码。生成代码的根据就是前文中说明的那些注解(annotation)以及使用这些annotation的类、接口。maven
总结起来就一句话,Dagger把你须要在悟空类里写的金箍棒类的初始化代码都根据注解替你自动生成了!只不过这种生成的代码比明晃晃的使用new
初始化的方法更加复杂一些。
把大象装冰箱一共分几步:
@Inject
注解修饰。XXXModule
。里面写的@Provides注解修饰的方法。这些@Provides方法返回“悟空类”和“金箍棒类”对象。好比@Provides Wukong provideWukong(){ return new Wukong(); }
@Component
注解修饰。通常叫作XXXComponent
。里面写一个注入方法:void inject(Wukong wk);
。这里Wukong
只是一个例子。任何你准备要注入的类均可以代替上面参数的Wukong
类。@Inject
的field。最后,Dagger会根据上面的内容和最后的@Component
接口生成一个DaggerXXXComponent
的类型,使用这个类型来实现注入。上面的1到3步能够理解为依赖的配置。最后的XXXComponent
代替古老的Reflect方式实现注入。
第一步的@Inject修饰的构造函数和`@Module`的`provideXXX`方法两者能够省略一个。 Dagger能够根据其中的任意一种配置建立依赖的对象。都写上等于有了双保险。
上文提到过屡次。Dagger 2厉害的地方就在于这个库彻底不用反射,而是用在编译期生成代码的方式实现的依赖注入。这个特色致使在Android Studio配置的时候须要作一些额外的工做。
这里假设你已经建立了一个新的Android应用项目。下面打开build.gradle
文件,咱们一步一步的来完成Dagger2的配置。
apply plugin: 'kotlin-android' // 非必须 apply plugin: 'kotlin-android-extensions' // 必须!!!
为何要加一个新的plugin呢?这个是为后面使用的kapt
和provided
提供支持的。gradle自己不支持这两个操做。
buildscript { ext.kotlin_version = '1.0.1-2' repositories { mavenCentral() } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" } }
dependencies { // ...其余略... compile 'com.google.dagger:dagger:2.2' kapt 'com.google.dagger:dagger-compiler:2.2' provided 'javax.annotation:jsr250-api:1.0' }
最后,同步Gradle。
下面就是Dagger一展身手的时候了。
悟空:
import javax.inject.Inject; /** * Created by uncle_charlie on 6/4/2016. */ public class Wukong { @Inject JinGuBang jinGuBang; @Inject public Wukong() { } public String useJinGuBang() { return this.jinGuBang.use(); } }
金箍棒:
import javax.inject.Inject; /** * Created by uncle_charlie on 6/4/2016. */ public class JinGuBang { @Inject public JinGuBang() { } public String use() { return "user Jing gu bang"; } }
@Inject
注解修饰。@Inject
注解。@Module
类建立@Module
注解的类,并在其中添加@Provides
注解修饰的方法。这些方法建立被依赖的对象。
import dagger.Module; import dagger.Provides; /** * Created by uncle_charlie on 6/4/2016. */ @Module public class XiYouModule { @Provides // @Singleton Wukong provideWukong() { return new Wukong(); } @Provides // @Singleton JinGuBang provideJinGuBang() { return new JinGuBang(); } }
@Singleton
注解代表,这个被依赖的对象在应用的生命周期里只有一个实例。@Provides
方法和前一步说到的@Inject
注解的构造函数两个能够只写一个。@Component
接口,链接@Module
和@Inject
@Module
和@Provides
方法提供了被依赖的对象。@Inject
在@Component
接口出现的地方则是指明了须要注入的地方(通常是一个field)。@Component
接口就是用来把他们链接起来的。
import android.app.Activity; import javax.inject.Singleton; import dagger.Component; /** * Created by uncle_charlie on 6/4/2016. */ @Component(modules = {XiYouModule.class}) @Singleton public interface XiYouComponent { void inject(Wukong wk); void inject(Activity a); }
其中inject()
方法里使用的对象,就是包含@Inject
的field的须要注入的对象。
在这个接口中也能够不用inject()
方法,而使用provideXXX()
方法后面会有更多介绍。
注意:@Component接口必定要在直接中指明@Module类型
@Component
接口获取对象通过前面的步骤,依赖和被依赖对象关系都已经配置好了。下面就来获取被依赖对象来注入依赖对象。
public class MainActivity extends AppCompatActivity { private static final String TAG = "##MainActivity"; @Inject Wukong wukong; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView welcomeTextView = (TextView) findViewById(R.id.welcome_textview); // 1 XiYouComponent xiYouComponent = DaggerXiYouComponent .builder() // 2 .xiYouModule(new XiYouModule()) .build(); xiYouComponent.inject(this); // 3 welcomeTextView.setText(wukong.useJinGuBang()); } }
首先主要到属性@Inject Wukong wukong;
已经在MainActivity
声明了。这里代表一个依赖关系:这个activity依赖于悟空,并准备注入悟空对象。
DaggerXiYouComponent
就是Dagger根据咱们的XiYouModule
类生成的代码。DaggerXiYouComponent
的builder
添加XiYouModule
的实例。若是这个Module只须要用到无参构造函数的话能够用一种省略用法:create()
方法。能够简写为:DaggerXiYouComponent .builder() // 2 //.xiYouModule(new XiYouModule()) //.build() .create();
inject(this)
方法以后注入即完成。因此能够直接使用@Inject Wukong wukong;
属性来调用方法:welcomeTextView.setText(wukong.useJinGuBang());
最后在activity中显示方法返回的文字。运行代码,看看结果吧。
以上内容能够归纳为:什么被依赖,就把什么放在@Module
类里(或者什么被依赖,就给什么添加@Inject
的无参构造函数)。什么有依赖(@Inject
属性),就把什么放在@Component
接口的inject()
方法参数里。(或者有什么@Inject
属性,就在@Component
接口里provide什么对象)。这个归纳不必定严密,可是基本用法所有包括了。
依赖注入是颇有用的。以上的内容只是Dagger2依赖注入的一部分。各位读者还须要根据官方文档多加练习才能更好的理解依赖注入和Dagger的各类用法。