Dagger.Android — Dagger2進階

一,前期基礎知識儲備

參考筆者之前的文章《依賴注入框架-Dagger2 精煉詳解》,裏面有Dagger2的常規用法——@Inject,@Component,@Module,@Provides這些基本註解。

這裏沿用上篇文章中示例,在Activity中完成一個類的注入,代碼如下:

public class HttpActivity extends AppCompatActivity {
 
    @Inject
    RetrofitManager retrofitManager;
 
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        DaggerHttpActivityComponent.builder()
                .httpActivityModule(new HttpActivityModule(100))
                .build().inject(this);
        Toast.makeText(this, retrofitManager.hashCode(), Toast.LENGTH_SHORT).show();
    }
}

實際上這裏違反了依賴注入的核心原則:一個類不應該知道自己是如何被注入的。但這裏我們還是可以通過builder方法和HttpActivityModule看出注入的過程,這顯然違反原則的。所以Dagger針對Android平臺提供了專門的庫來簡化注入過程,使用時需要添加依賴庫:

    //Dagger
    compile 'com.google.dagger:dagger:2.11'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.11'
    //Dagger-Android
    compile 'com.google.dagger:dagger-android:2.11'
    compile 'com.google.dagger:dagger-android-support:2.11' 
    annotationProcessor 'com.google.dagger:dagger-android-processor:2.11'

在Android中Dagger的注入是分層級的。有對應用層級全局屬性或者服務(OKHttp,Database,Retrofit等)的注入;有對Activity的變量的注入,也有對Fragment中的變量的注入,對應的Component的層級如圖:

Component的層級
Component的層級

二,上代碼,具體實現

模擬MainActivity注入User對象 — 往Activity中注入簡單的對象類型的變量

public class User {

    String name;

    @Inject
    public User() {
        this.name  = "Leon";
    }

}

1)創建MainActivitySubComponent

@Subcomponent
public interface MainActivitySubComponent extends AndroidInjector<MainActivity> {

    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<MainActivity>{}
}

* MainActivitySubComponent是MainActivity對應的Component;

* 它是應用層級Component的子Component,所以使用@Subcomponent進行註解。

* MainActivitySubComponent繼承自AndroidInjector,AndroidInjector是Android中核心類(Activity,Fragment)的注入器;

* 用以完成對Activity或Fragment成員變量的注入。

* 另外還需要創建一個繼承自AndroidInjector.Builder的抽象類Builder,可以用它來創建MainActivitySubComponent的實例。

 

2)創建ActivityModule

@Module(subcomponents = MainActivitySubComponent.class)
public abstract class ActivityModule {

    // 返回MainActivity對應的注入器工廠
    @Binds
    @IntoMap
    @ActivityKey(MainActivity.class)
    abstract AndroidInjector.Factory<? extends Activity> 
        bindMainActivityInjectorFactory(MainActivitySubComponent.Builder builder);

    // 返回其他Activity對應的注入器工廠
}

* ActivityModule可以提供各個Activity對應的AndroidInjector.Factory,也就是注入器工廠類

* subcomponents指定爲MainActivitySubComponent,表示MainActivitySubComponent是任何使用ActivityModule的Component的子Component

 

3)創建應用層級的AppComponent

@Component(modules = {AndroidInjectionModule.class, ActivityModule.class})
public interface AppComponent {
    void inject(DemoApplication instance);
}

* 創建應用層級的AppComponent;

* 應用層級的AppComponent安裝了兩個Module,一個是AndroidInjectionModule(dagger-android庫提供);

* 另一個是ActivityModule,上一步中自定義好的。

* 由於AppComponent使用了ActivityModule,所以AppComponent是MainActivitySubComponent的父Component。

* AppComponent中還提供了注入到Application類中的注入方法inject。

* 值得注意的是,inject方法中的參數爲我們自定義的DemoApplication,而非Application類型。

 

4)注入到Application類中

public class DemoApplication extends Application implements HasActivityInjector {

    @Inject
    DispatchingAndroidInjector<Activity> dispatchingAndroidInjector;

    @Override
    public void onCreate() {
        super.onCreate();
        DaggerAppComponent.create().inject(this);
    }

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

*在應用的Application類中,需要實現接口HasActivityInjector返回一個全局的Activity的注入器dispatchingAndroidInjector;

* 而它的初始化將由AppComponent來完成,即由AppComponent對應生成的DaggerAppComponent在Application類的onCreate方法中注入。

 

5)注入到MainActivity

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Inject
    User mUser;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        /*MainActivity中User對象的注入*/
        /*通過以上步驟就完成了對Activity的注入*/
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);

        Log.d(TAG, "onCreate: User is " + mUser.name);
    }
}

* 在MainActivity的onCreate方法中,調用super.onCreate()方法前使用AndroidInjection對MainActivity進行注入。

* 這個注入過程又是怎麼完成的呢?

* AndroidInjection 注入時會獲取Application中的dispatchingAndroidInjector

* 通過dispatchingAndroidInjector查找對應MainActivity的AndroidInjector.Factory

* (即MainActivitySubComponent類中的Builder,該Builder實現了AndroidInjector.Factory接口);

* 然後使用Builder創建MainActivity的注入器AndroidInjector(即MainActivitySubComponent);

* 最終使用MainActivitySubComponent實現對MainActivity的注入,完成User對象實例的賦值

 

6)@ContributesAndroidInjector

    @Module
    abstract class ActivityModule {
        @ContributesAndroidInjector
        abstract MainActivity contributeMainActivityInjector();
    }

* 當我們想要注入某個Activity中,就必須創建該Activity對應的Component,而且這些代碼都是模板代碼,不需要動腦子。

* 另外每增加一個Component,就要在ActivityModule的subcomponents集合中添加它。

* 事實上,Activity對應Component的創建可以使用註解@ContributesAndroidInjector自動生成。

 

首先,需要再次添加註解處理器的依賴:

annotationProcessor 'com.google.dagger:dagger-android-processor:2.11'

然後,修改ActivityModule代碼如上即可。

 

以上,就是使用Dagger專屬Android庫注入對象類型成員變量的用法。注入Fragment也是類似的方法。

 

推薦一篇好文:《Dagger2與AndroidInjector

筆者,做了一副代碼對比圖,可以清晰地看到,二者的實現是類似的。

Dagger-Android
Dagger-Android

* 一個@SubComponent;

* 一個@Component;

* 一個@Module;

* 一個自定義Application;

* 一個注入Activity。

依賴注入的對象,可以是@Inject標記的,也可以是@Module和@Provides標記好的。

 

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