1. 程式人生 > >依賴注入之Dagger2初探

依賴注入之Dagger2初探

何為Dagger2

Dagger2是Google提供的依賴注入框架,依賴注入為Android中元件之間的解耦提供了很好的解決方案。
使用它可以自動生成建立依賴關係所需要的程式碼。減少很多模板化的程式碼,更易於測試,降低耦合,建立可複用可互換的模組。已經在越來越多的開源專案中被使用,其已經發展成為未來的一個技術趨勢。

為什麼要使用Dagger2

MVP設計模式中,M層提供資料,V層做介面展示,而P層則成為M和V的橋樑,這其中就必然涉及到M和V的互動及處理,如果業務複雜或者多個頁面共用,它還是面臨著高度的耦合性。如果需求發生變動,必然需要更改P中的內容。而在MVP中,我們通常在activity層中需要拿到p層的物件,那麼在開發中有可能我們很多activity或者fragment都可能需要拿到這個p層物件的例項,假如我們P層類的構造發生變化(例如增加了引數)我們要在很多地方都得進行修改,這就是耦合度太高的弊端。

為了解決這種耦合性的問題,有一幫牛叉的人就思索著:能不能有個容器,這個容器在我們需要用到某個物件的時候幫我們建立好需要的物件,像物件工廠一樣,並且幫我們管理這些物件。當發生變化時,我們只需要換一個容器就可以了。就這樣,dagger2應運而生。

如何理解Dagger2

簡而言之,dagger2中組成內容的對應關係:

  • 類Module:使用@Module修飾,裝載物件的容器。

  • 介面Component:使用@Component修飾,存放這些容器的倉庫。它是連線Module和依賴注入物件的橋樑。

  • 註解@Provides:該容器建立物件的動作。

  • 註解@Inject:從容器中取出這個物件的動作。

  • 註解@Qualifier:用來給@Inject和@Provides貼上關聯標籤(進行註解)。如果一個物件可以由一個或多個容器的@Provides修飾提供,這時候就需要用Qualifier進行標籤關聯。 還不清楚的可點選瞭解.

  • 註解@Scope:從容器取出物件的有效期,即生命週期。

Dagger2的核心使用流程:

  • 1.使用@Module修飾編寫Module,再通過@Provides修飾該物件的建立方法。

  • 2.使用@Component的modules屬性修飾存放Module容器的倉庫Component,並同時定義依賴注入的介面方法inject,引數為依賴注入的物件。

  • 3.執行編譯,使用自動生成的[”Dagger” + Component名]類先裝載Module,再用之前定義的依賴注入介面方法,最後在注入物件上新增@Inject進行注入關聯。

如何使用Dagger2

1.增加Dagger2依賴包

dependencies {
    //Dagger2
    implementation 'com.google.dagger:dagger:2.13'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.13'

    implementation 'com.google.dagger:dagger-android:2.13'
    implementation 'com.google.dagger:dagger-android-support:2.13'
    annotationProcessor 'com.google.dagger:dagger-android-processor:2.13'

    compileOnly 'org.glassfish:javax.annotation:10.0-b28'

    //ARouter
    compile 'com.alibaba:arouter-api:1.3.1'
    annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'

    //butterknife的sdk
    implementation 'com.jakewharton:butterknife:8.8.1'
    annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
}

2.編寫Module

@Module
public class LoginModule {
    @ActivityScope
    @Provides
    LoginPresenter getPresenter() {
        return new LoginPresenter();
    }

}

3.編寫Component裝載module

(1)使用Dagger2單獨編寫Component裝載module

@ActivityScope
@Component(modules = {LoginModule.class})
public interface LoginComponent {
    void inject(LoginActivity activity);
}

(2)使用Dagger-Android 統一生成裝載module

@ActivityScope
@ContributesAndroidInjector(modules = LoginModule.class)
abstract LoginActivity contributeSecondActivityInjector();

4.編譯工程

  AndroidStudio -> Build -> Make Project

5.進行依賴注入

(1)使用Dagger2,通過Component取出module注入依賴

@Override
protected void onResume() {
   super.onResume();
   DaggerLoginComponent.builder().loginModule(new LoginModule()).build().inject(this);
   mPresenter.attachV(this);
}

(2)使用Dagger-Android在BaseActivity中統一AndroidInjection統一取出module注入依賴

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    AndroidInjection.inject(this);  //統一注入
    super.onCreate(savedInstanceState);
    setContentView(getLayoutId());
}

Dagger2使用中存在的問題

1.看過上面介紹後,可能有人會疑問:一個Component難道只能儲存一個依賴注入物件的所有module?那豈不是我需要建立很多的Component實現介面,而且還有很多重複的勞動,多了也同樣不好管理。能不能使用一個Component,對多個依賴注入物件進行Module的儲存呢?

2.在Android中,我們需要進行依賴注入的物件大多數是Activity、Fragment、Service、BroadcastReceiver等,如果像上面那樣使用Dagger進行依賴注入的話,就需要為每個Activity、Fragment等建立Component和Module,並在生命週期中寫上一長串依賴注入的實現,這樣會顯得非常麻煩,那麼能否有一種方式,能夠將他們的所有依賴注入資訊統一註冊在一個全域性Component(AppComponent)中,並在每次Activity、Fragment等建立的時候自動進行依賴注入,這樣就完全實現了依賴注入的可配置,每個類都無需關注依賴注入如何實現。

那麼如何解決以上問題呢?Google為此不懈努力,開發出了Dagger2-android庫。

何為Dagger2-android

Dagger2-Android是Google基於Dagger2開發的應用於Android開發的擴充套件庫。通過它,我們能夠通過簡單的配置,無需書寫過多的Component就可以輕鬆地實現Android的依賴注入。可以說是Android實現依賴注入的一大法寶。

如何使用Dagger2-android進行全域性依賴配置

1.我們先宣告我們的Application類,並實現HasActivityInjector介面,然後新增到manifest清單檔案中:

public class MyApplication extends Application implements HasActivityInjector {
    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

    @Override
    public void onCreate() {
        super.onCreate();

        AppInjector.init(this); //全域性依賴注入

    }

    @Override
    public AndroidInjector<Activity> activityInjector() {
        return dispatchingAndroidInjector;
    }
}

2.定義全域性依賴倉庫AppComponent,新增依賴注入的Module。

@Singleton
@Component(modules = {
        AndroidInjectionModule.class,
        AndroidSupportInjectionModule.class,
        ActivitysModule.class
})
public interface AppComponent {
    void inject(MyApplication myApplication);
}

3.定義基礎Activity的Subcomponent–ActivitySubComponent,統一Activity的依賴注入介面:

在實際使用Dagger2過程中,我們不可能書寫過多的Component,那樣可讀性和可維護性都會大大降低,@Subcomponent主要解決的是就是Component複用的問題。
Subcomponent就好比將多個統一(類似)的依賴注入Component介面打包到一個Module(暫記為AllModule)中,而這些Subcomponent又可以放入多個Module。

這樣在外層我們只需要定義一個全域性的父Component,而在這個父Component中,我們放入了裝載了多個Subcomponent的AllModule。這樣如果我們需要新新增依賴的話,只需要在AllModule中進行Module註冊即可,無需新增新的Component,而且也方便管理。

@Subcomponent(modules = {
        AndroidInjectionModule.class,
})
public interface ActivitySubComponent extends AndroidInjector<BaseActivity> {

    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<BaseActivity> {  //構建規則
    
    }

}

4.定義存放多個ActivitySubComponent的Module–ActivitysModule:

@Module(subcomponents = {
        ActivitySubComponent.class
})
public abstract class ActivitysModule {

    @ActivityScope
    @ContributesAndroidInjector(modules = LoginModule.class)
    abstract LoginActivity contributeLoginActivityInjector();

    @ActivityScope
    @ContributesAndroidInjector(modules = MainModule.class)
    abstract MainActivity contributeMainActivitytInjector();

}

5.在全域性依賴倉庫AppComponent中裝入ActivitysModule,並進行全域性依賴注入:

使用Application註冊Activity生命週期回撥,在Activity建立的時候自動進行依賴注入。

DaggerAppComponent.builder().build().inject(myApplication);
        myApplication
                .registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
                    @Override
                    public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                        AndroidInjection.inject(activity);   //動態自動進行依賴注入
                    }
                 ···省略其他Callbacks
                 
                });

需要了解更多有關Dagger2和MVP內容的,請點選檢視

更多框架演示