dagger2是一个依赖注入框架,依赖注入框架主要用于模块间解耦,提高代码的健壮性和可维护性。
官方简介:https://google.github.io/dagger/
本文示例完整代码(官方代码整理到一个工程里):
参考博客:
- https://my.oschina.net/u/994565/blog/702385
- http://blog.csdn.net/wds1181977/article/details/51822043
在Android Studio工程下的根目录的build.gradle文件里加入
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.7'
完整代码如下:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.7'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
在需要用到dagger2的模块里添加
apply plugin: 'com.neenbedankt.android-apt' apt 'com.google.dagger:dagger-compiler:2.8' compile 'com.google.dagger:dagger:2.8'
完整代码如下:
apply plugin: 'com.android.application' apply plugin: 'com.neenbedankt.android-apt' android { compileSdkVersion 24 buildToolsVersion "25.0.1" defaultConfig { applicationId "android.daggerexamples.google.googleexamples" minSdkVersion 9 targetSdkVersion 24 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) apt 'com.google.dagger:dagger-compiler:2.8' compile 'com.google.dagger:dagger:2.8' compile 'com.android.support:appcompat-v7:24.2.1' testCompile 'junit:junit:4.12' }
APT(Annotation processing tool) 是一种处理注释的工具,它对源代码文件进行检测找出其中的Annotation,使用Annotation进行额外的处理。Annotation处理器在处理Annotation时可以根据源文件中的Annotation生成额外的源文件和其它的文件(文件具体内容由Annotation处理器的编写者决定),
APT还会编译生成的源文件和原来的源文件,将它们一起生成class文件.使用APT主要的目的是简化开发者的工作量,因为APT可以编译程序源代码的同时生成一些附属文件(比如源文件类文件程序发布描述文件等),这些附属文件的内容也都是与源代码相关的,换句话说,使用APT可以代替传统的对代码信息和附属文件的维护工作。
dagger2主要注解有:@Modules,@Provide,@Scope,@Qualifier,@Inject,@Component,
@Module:
- Modules类里面的方法专门提供依赖,所以我们定义一个类,用@Module注解,这样Dagger在构造类的实例的时候,就知道从哪里去找到需要的 依赖。modules的一个重要特征是它们设计为分区并组合在一起(比如说,在我们的app中可以有多个组成在一起的modules)。
@Inject:
- 通常在需要依赖的地方使用这个注解。换句话说,你用它告诉Dagger这个类或者字段需要依赖注入。这样,Dagger就会构造一个这个类的实例并满足他们的依赖。
- @Inject标记的成员变量会以调用了@Component的inject(x)方法后初始化实例,初始化顺序如下
public interface ApplicationComponent { void inject(DemoApplication application);//一定要是具体的类,不能是父类。 void inject(HomeActivity homeActivity); void inject(DemoActivity demoActivity); }
-
有两种方式可以提供依赖,一个是注解了@Inject的构造方法,一个是在Module里提供的依赖,那么Dagger2是怎么选择依赖提供的呢,规则是这样的:
- 步骤1:查找Module中是否存在创建该类的方法。
- 步骤2:若存在创建类方法,查看该方法是否存在参数
- 步骤2.1:若存在参数,则按从步骤1开始依次初始化每个参数
- 步骤2.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束
- 步骤3:若不存在创建类方法,则查找Inject注解的构造函数,看构造函数是否存在参数
- 步骤3.1:若存在参数,则从步骤1开始依次初始化每个参数
- 步骤3.2:若不存在参数,则直接初始化该类实例,一次依赖注入到此结束
@Provide: 在modules中,我们定义的方法是用这个注解,以此来告诉Dagger我们想要构造对象并提供这些依赖。
@Module public class AndroidModule { @Provides @Singleton LocationManager provideLocationManager() { return (LocationManager) application.getSystemService(LOCATION_SERVICE); } }
@Component:
- Components从根本上来说就是一个注入器,也可以说是@Inject和@Module的桥梁,它的主要作用就是连接这两个部分。 Components可以提供所有定义了的类型的实例,比如:我们必须用@Component注解一个接口然后列出所有的@Modules组成该组件,如 果缺失了任何一块都会在编译的时候报错。所有的组件都可以通过它的modules知道依赖的范围。
@Scope:
Scopes可是非常的有用,Dagger2可以通过自定义注解限定注解作用域。
@Scope @Retention(RUNTIME) public @interface PerActivity {}
Qualifier:
当类的类型不足以鉴别一个依赖的时候,我们就可以使用这个注解标示。例如:在Android中,我们会需要不同类型的context,所以我们就可以定义 qualifier注解“@ForApplication”和“@ForActivity”,这样当注入一个context的时候,我们就可以告诉 Dagger我们想要哪种类型的context。
dagger2官方简单的例子:一个Module,一个Component,然后使用依赖注入初始化@Inject注解的成员变量
@Qualifier @Retention(RUNTIME) public @interface ForApplication { }
@Module public class AndroidModule { private final DemoApplication application; public AndroidModule(DemoApplication application) { this.application = application; } /** * Allow the application context to be injected but require that it be annotated with * {@link ForApplication @Annotation} to explicitly differentiate it from an activity context. */ @Provides @Singleton @ForApplication Context provideApplicationContext() { return application; } @Provides @Singleton LocationManager provideLocationManager() { return (LocationManager) application.getSystemService(LOCATION_SERVICE); } }
上面的类用@Module声明了一个Module,并且用@Provides声明了这个Module能提供注入LocationManager和Context实例。
public class DemoApplication extends Application { @Singleton @Component(modules = AndroidModule.class) public interface ApplicationComponent { void inject(DemoApplication application); void inject(HomeActivity homeActivity); void inject(DemoActivity demoActivity); } @Inject LocationManager locationManager; // for some reason. private ApplicationComponent component; @Override public void onCreate() { super.onCreate(); component = DaggerDemoApplication_ApplicationComponent.builder() .androidModule(new AndroidModule(this)) .build(); component().inject(this); // As of now, LocationManager should be injected into this. } public ApplicationComponent component() { return component; } }
@Component声明了一个ApplicationComponent,并且void inject(xxx),声明只能在DemoApplication,HomeActivity,DemoActivity几个类的实例里注入。
component = DaggerDemoApplication_ApplicationComponent.builder() .androidModule(new AndroidModule(this)) .build();这是构建了一个ApplicationComponent实例,
component().inject(this),调用这一句后,会初始化并给@Inject声明的 LocationManager locationManager对象初始化值。
DaggerDemoApplication_ApplicationComponent类不是我们手动新建的,是自动生成的。
使用Android Studio 的Build->Make Project/Make Module '模块名',会看到自动生成了以下代码
DaggerDemoApplication_ApplicationComponent这个类是就是自动生成的。
未完待续