when the android meet dagger2

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

結果:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章