一,前期基礎知識儲備
參考筆者之前的文章《依賴注入框架-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的層級如圖:
二,上代碼,具體實現
模擬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》
筆者,做了一副代碼對比圖,可以清晰地看到,二者的實現是類似的。
* 一個@SubComponent;
* 一個@Component;
* 一個@Module;
* 一個自定義Application;
* 一個注入Activity。
依賴注入的對象,可以是@Inject標記的,也可以是@Module和@Provides標記好的。