What is dagger2?
dagger是一个依赖注入框架,不同于传统的依赖注入框架的是,dagger的代码是使用代码生成器进行机器生成,区别于传统的DI框架依赖反射。所以,dagger2更适合于android开发。并且,dagger2是基于JSR330,通过@Inject注解标示依赖,这个注解可用于方法(method),域(field),构造函数(ctor)。
我们可以先看一下dagger2中的注解:
Module是用来注解依赖注入上下文(dependency injection context),该类定义了一系列用于注解的对象集合。而这个类中的方法如果返回依赖的对象,那么就应该使用@Provides进行注解。如果你希望返回的对象应该是个实体类(单例的),那么可以和@Singletion进行注解,那么只会返回同一个实例。
我们可以看到@Inject定义了需要DI的地方,而Modlue则是对象的提供者,那么到这里,我们必定需要一种机制作为桥梁,来连接二者,这就是@Component的作用,@Component是用于interface的注解,这个接口会被Dagger2用来生成代码,通常生成的代码都是有固定的范式的,比如,在这个接口名之前加一个Dagger作为前缀。这个生成的代码有一个create方法,它被用于配置对象(我们稍后会看到)
HOW TO USE:
对于Android Studio 需要在工程的gradle中添加如下代码
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:1.5.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' //添加apt命令
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' 用于添加apt命令 然后切换到app的gradle中![]()
代码如下:
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.chan.daggerdemo"
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
apt 'com.google.dagger:dagger-compiler:2.0.2' //指定注解处理器
compile 'com.google.dagger:dagger:2.0.2' //dagger公用api
provided 'org.glassfish:javax.annotation:10.0-b28' //添加android缺失的部分javax注解
}
Example:
package com.vogella.android.dagger2simple;
public class NetworkApi {
public boolean validateUser(String username, String password) {
// imagine an actual network call here
// for demo purpose return false in "real" life
if (username == null || username.length() == 0) {
return false;
} else {
return true;
}
}
}
对于NetworkApi我们需要一个Moudle来生产它的对象:
package com.vogella.android.dagger2simple.modules;
import com.vogella.android.dagger2simple.NetworkApi;
import javax.inject.Singleton;
import dagger.Module;
import dagger.Provides;
@Module
public class NetworkApiModule {
@Provides
@Singleton
public NetworkApi getNetwork(){
return new NetworkApi();
}
}
getNetwork用于创建NetworkApi,并且还是单例的创建
package com.vogella.android.dagger2simple.components;
import android.app.Activity;
import com.vogella.android.dagger2simple.MainActivity;
import com.vogella.android.dagger2simple.NetworkApi;
import com.vogella.android.dagger2simple.modules.NetworkApiModule;
import javax.inject.Singleton;
import dagger.Component;
@Singleton
@Component(modules = {NetworkApiModule.class})
public interface DiComponent {
// to update the fields in your activities
void inject(MainActivity activity);
}
点击build将会生成代码,这时候我们在application里面创建注入上下文,并且提供方法来访问:
package com.vogella.android.dagger2simple;
import android.app.Application;
import com.vogella.android.dagger2simple.components.DaggerDiComponent;
import com.vogella.android.dagger2simple.components.DiComponent;
public class MyApplication extends Application {
DiComponent component;
@Override
public void onCreate() {
super.onCreate();
component = DaggerDiComponent.builder().build();
}
public DiComponent getComponent() {
return component;
}
}
配置一下AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.vogella.android.dagger2simple" >
<application
android:name="MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
我们可以看到DiComponent接口,它有一个inject方法,该方法的参数就是需要DI的类,你可以把它想象成容器,而Moudle是产生对象的,这些对象通过Component注入到容器当中,所以你可以看到:
package com.vogella.android.dagger2simple;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
import javax.inject.Inject;
public class MainActivity extends Activity {
@Inject NetworkApi networkApi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
((MyApplication) getApplication()).getComponent().inject(this);
boolean injected = networkApi == null ? false : true;
TextView userAvailable = (TextView) findViewById(R.id.target);
userAvailable.setText("Dependency injection worked: " + String.valueOf(injected));
}
}
NetworkApi 便成功的注入到了MainActivity中,值得注意的是,需要配注入的域不能是私有级别的!
结果: