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中,值得注意的是,需要配注入的域不能是私有級別的!
結果: