Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android系列之Dagger2使用解析

Android系列之Dagger2使用解析

編輯:關於Android編程

前言

現在Dagger2在項目中的使用越來越多,Dagger2是Dagger的升級版本,Dagger沒有使用過,但是本篇說的是Dagger2,主要講解的是Dagger2是如何使用的。對了,忘了說Dagger其實是一個依賴注入的框架。

什麼是依賴注入

依賴注入是一種面向對象的編程模式,它的出現是為了降低耦合性,所謂耦合就是類之間依賴關系,所謂降低耦合就是降低類和類之間依賴關系。可能有的人說自己之前並沒有使用過依賴注入,其實真的沒有使用過嗎?當我們在一個類的構造函數中通過參數引入另一個類的對象,或者通過set方法設置一個類的對象其實就是使用的依賴注入。

通常依賴注入有以下幾種方式

通過接口注入
interface ClassBInterface {
    void setB(ClassB b);
}
public class ClassA implements ClassBInterface {
    ClassB classB;
    @override
    void setB(ClassB b) {
    classB = b;
    }
}
通過set方法注入
public class ClassA {
    ClassB classB;  
    public void setClassB(ClassB b) {
      classB = b;
    }
}
通過構造方法注入
public class ClassA {
    ClassB classB;
    public void ClassA(ClassB b) {
        classB = b;
    }
}
通過注解的方式注入
public class ClassA {
    //此時並不會完成注入,還需要依賴注入框架的支持,如Dagger2
    @inject 
    ClassB classB;
    public ClassA() {}
}

下面我們就來說說如何通過Dagger2來實現依賴注入吧。

引入Dagger2

添加apt插件

dependencies {
        classpath 'com.android.tools.build:gradle:2.1.2'
        //添加apt插件
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
    }

添加依賴(在build.gradle中添加如下代碼)

apply plugin: 'com.android.application'
    //添加如下代碼,應用apt插件
    apply plugin: 'com.neenbedankt.android-apt'
    ...
    dependencies {
    ...
    compile 'com.google.dagger:dagger:2.4'
    apt 'com.google.dagger:dagger-compiler:2.4'
    //java注解
    compile 'org.glassfish:javax.annotation:10.0-b28'
    ...
}

使用Dagger2

添加完Dagger的依賴後我們如何在項目中使用Dagger呢?

在項目中絕大多數的使用都是Dagger結合MVP架構使用的,在MVP中使用是非常典型的降低耦合的使用。不懂MVP的可以看這裡。
本篇文章中的示例是一個簡單的登陸功能的示例,代碼沿用上篇講解MVP的登陸代碼,看這裡,該示例采用MVP架構設計通過Dagger2進行解耦合,下面就來看看如何使用吧。

在使用Dagger2前我們最好簡單的了解一下MVP,主要是為了理解本篇中的代碼。簡單了解MVP即使不會寫MVP也可以看的懂本篇的代碼。

為什麼要選擇在MVP模式中使用Dagger2呢?因為在MVP模式中Activity持有presenter的引用,同時presenter也持有view的引用,這樣便於更新UI界面,這樣Activity就和presenter僅僅的耦合在一起了,
而Dagger2是依賴注入框架就是解耦合的,所以子MVP中使用Dagger2也就再好不過了。
在上篇文章講解MVP時我們可以明顯的看到如下代碼

public class LoginActivity extends AppCompatActivity implements ILoginView,View.OnClickListener{
    private Button mLogin ;
    private Button mClear ;
    private EditText mName ;
    private EditText mPassWord ;
    ILoginPresenter loginPresenter ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mLogin = (Button) findViewById(R.id.btn_login);
        mClear = (Button) findViewById(R.id.btn_clear);
        mName = (EditText) findViewById(R.id.et_name);
        mPassWord = (EditText) findViewById(R.id.et_password);

        mLogin.setOnClickListener(this);
        mClear.setOnClickListener(this);

        //持有presenter的引用並且創建對象
        loginPresenter = new LoginPresenterCompl(this) ;

    }
    ........
}

在上述代碼中可以看到activity持有了presenter的引用並且創建了該對象,但是如果presenter的構造函數發生改變則這裡也需要改變,其實所有和presenter構造函數相關的代碼都要改變。

但是如果我們使用Dagger2依賴框架該如何使用呢?請看下面代碼

activity中的代碼

public class LoginActivity extends AppCompatActivity implements ILoginView,View.OnClickListener{

    ..........

    //注意此處使用了注解
    @Inject
    LoginPresenterCompl loginPresenter ;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mLogin = (Button) findViewById(R.id.btn_login);
        mClear = (Button) findViewById(R.id.btn_clear);
        mName = (EditText) findViewById(R.id.et_name);
        mPassWord = (EditText) findViewById(R.id.et_password);
        mLogin.setOnClickListener(this);
        mClear.setOnClickListener(this);
        DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this);

    }
    .......
}

LoginPresenterCompl中的代碼

public class LoginPresenterCompl implements ILoginPresenter {
        private ILoginView loginView ;
        private User user ; 
        //注意此處使用了注解
        @Inject
        public LoginPresenterCompl(ILoginView view){
            loginView = view ;
            user = new User("張三","123456") ;
        }
        ......
    }

只有上述兩個注解還無法完成依賴注入,還需要如下兩個新增類

新增的MainModule類

@Module
public class MainModule {
    private final ILoginView view ;
    public MainModule(ILoginView view){
        this.view = view ;
    }
    @Provides
    ILoginView provideILogView(){
        return view ;
    }
}

新增的MainComponent接口

@Component(modules = MainModule.class)
public interface MainComponent {
    public void inject(LoginActivity activity) ;
}

通過直接注解和上述兩個接口類即可完成Dagger2的依賴注入。
在LoginActivity中是通過

DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this)

完成依賴注入的。

看完上面的代碼後,一臉的懵逼,WTF(what the fuck),這TM是什麼,這麼復雜,還不如之前的簡單呢,新增了兩個類還有這麼多代碼,得不償失呀!

同志們,如果你們第一眼看到後是這樣想的話,說明和我想的一樣,呵呵。每一個剛接觸Dagger2的人可能都會這樣想,因為我們只看到了表面。

不錯,表面上我們是多了一個類和接口也多了很多代碼,但是這樣的組合其實是可以理解的。因為通常簡單的代碼具有耦合性,而要想降低這樣的耦合就需要其他的輔助代碼,其實少代碼量和低耦合這兩者並不能同時兼顧,古人雲:魚和熊掌不可兼得。我們作為堂堂聰明絕頂的程序猿怎麼可能會輸給古人呢。

好!下面來認真講解Dagger2是如何完成依賴注入的。

首先我們來看看LoginActivity代碼

LoginActivity中有這麼一段代碼

@Inject
LoginPresenterCompl loginPresenter ;

同樣在LoginPresenterCompl中也有這麼一段代碼

@Inject
public LoginPresenterCompl(ILoginView view){
    loginView = view ;
    user = new User("張三","123456") ;
}

之所以挑出這兩段代碼是因為它們都添加了@Inject注解。

在LoginActivity中其實只有這麼一句提到loginPresenter,在接下來的代碼中並沒有對其進行初始化。
那loginPresenter是如何進行初始化的呢(此處注意添加@Inject注解的變量不能被private修飾)?

直觀上我們可以這樣理解,被@Inject注解的代碼存在某種聯系,當代碼執行到@Inject的時候程序會自動進入到這個類的構造方法中,如果正巧這個構造方法也被@Inject修飾了,那麼系統就會幫我們自動創建對象。

這只是表面的理解,這其中肯定還有很多我們沒有看到的“貓膩”。這倆不會無緣無故的有聯系,肯定還有第三者,通過這個第三者這兩個被@Inject注解修飾的代碼才會產生聯系。

這個第三者是誰呢?自然的我們就會想到我們添加的這個類和接口。

首先我們來分析MainComponent接口

代碼如下

@Component(modules = MainModule.class)
public interface MainComponent {
    public void inject(LoginActivity activity) ;
}

MainComponent是一個接口(也可以是一個抽象類),在這個接口中我們定義了一個inject()方法,其中參數是LoginActivity對象,同時MainComponent還被@Component注解著,注解中modules的值是MainModule.class,這個內容會在接下來的地方進行說明,暫時先放一放。

此時在Android studio中,如果我們rebuild的一下項目就會有新的發現。在項目的build/generated/source/apt/debug/項目包名/dragger目錄下生成對應的包其中包含DaggerMainComponent類,這個類名其實不是固定的,是根據我們上面寫的MainComponent,加了Dagger前綴生成的DaggerMainComponent。
其實在這個時候我們就已經完成了present的依賴注入。

但是在

DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this)

中我們看到還有一個MainModule,這個是我們自己創建的一個類

MainModule代碼如下

@Module
public class MainModule {
    private final ILoginView view ;
    public MainModule(ILoginView view){
        this.view = view ;
    }
    @Provides
    ILoginView provideILogView(){
        return view ;
    }
}

我們可以看到這個類被@Module注解修飾,內部有一個ILoginView的變量和一個構造方法還有一個被@Provides修飾的provideILogView方法。

看到這還是一臉懵逼,這個類是干嘛的?

在MainComponent接口中我們看到這麼一個注解@Component(modules = MainModule.class),這裡用到了MainModule,可見MainComponent需要MainModule一起才能完成工作。

其實這個類我們可以理解成提供參數的,也就是提供參數依賴的,如何理解呢?

在MainModule中我們為什麼要提供ILoginView類型的對象?為什麼不是其他的呢?
這是因為LoginPresenterCompl的構造函數需要這麼一個參數,所以我們在這裡提供這麼一個相同的參數,並通過被@Provides注解修飾的方法將其返回出去,如果LoginPresenterCompl還需要其他的參數,同樣我們也可以在這裡添加對應類型的參數然後通過另一個被@Provides注解修飾的方法返回出去。

在MainComponent接口中提供的inject()方法的參數是LoginActivity,這個參數的含義是LoginPresenter要在什麼地方注入。

了解了各個類的功能後我們來總結一下

@Inject 程序會將Dagger2會將帶有此注解的變量或者構造方法參與到依賴注入當中,Dagger2會實例化這個對象

@Module 帶有該注解的類需要對外提供依賴,其實就是提供實例化需要的參數,Dagger2在實例化的過程中發現一些參數,Dagger2就會到該類中尋找帶有@Provides注解的以provide開頭的需找對應的參數

@Component 帶有該注解的接口或抽象類起到一個關聯橋梁的作用,作用就是將帶有@Inject的方法或對象和帶有@Module的類進行關聯,只有通過該接口或抽象類才可以在實例化的時候到帶有
@Module中類中去尋找需要的參數,也就是依賴注入。

OK,下面我們來捋捋思路。

1、在這個示例代碼中,LoginActivity中需要LoginPresenterCompl,所以在LoginActivity中定義了該對象並且通過@Inject將其注解,同時到LoginPresenterCompl的構造方法中也通過@Inject將其注解,
表明這些是需要依賴注入的。

2、因為在LoginPresenterCompl的構造方法需要ILoginView類型的參數,所以需要通過依賴將獲取這些參數,所以就需要帶有@Module注解的類用於獲取需要的參數,
在@Module注解的類中通過被@Provides注解的以provide開頭的方法對外提供需要的參數,一般而言有幾個參數就需要有幾個帶有@Provides的方法。

3、此時還需要一個橋梁將兩者聯系到一起,帶有@Component的接口或抽象類就起到這個橋梁的作用。注解中有一個module的值,這個值指向需要依賴的Module類,同時其中有一個抽象方法
inject(),其中的參數就是我們需要在哪個類中實例化LoginPreserentCompl,因為我們需要在LoginActivity中實例化,所以參數類型就是LoginActivity類型。
然後在Android studio中rebuild我們的項目,就會生成DaggerMainComponent類,通過

DaggerMainComponent.builder().mainModule(new MainModule(this)).build().inject(this);

完成我們需要的依賴注入。

總結

可能我們通過上面的講解,知道了如何使用Dagger2了,也知道具體的流程了,但是可能還會有些疑惑,為什麼?Dagger2是如何通過一些接口和類就完成依賴注入的?

在此聲明,別著急,知道如何使用這只是第一步,在下一篇文章中將會講解Dagger2實現依賴注入的原理。敬請期待!!!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved