一、依賴注入是什么枚钓?
曾幾何時(shí)铅搓,項(xiàng)目中每個(gè)依賴單例Manager的地方,getInstance()方法是必不可少的搀捷。
public class AccountManager {
private static class Holder {
private static final AccountManager instance = new AccountManager();
}
public static AccountManager getInstance() {
return Holder.instance;
}
private AccountManager() {
// Other instance
}
...
}
每次像這樣寫一遍真是挺煩人的星掰,如果內(nèi)部再有一些依賴的話,會(huì)變得更加撲朔迷離嫩舟。
public class App extend Application {
private AccountManager mAccount;
private NetworkManager mNet;
private DatabaseManager mDb;
...
@Override
public void onCreate() {
super.onCreate();
mAccount = AccountManager.getInstance();
mNet= NetworkManager.getInstance(this, mAccount);
mDb= DatabaseManager.getInstance(this, "app.db", 1);
}
...
}
這只是簡(jiǎn)單的例子氢烘,遇到大型項(xiàng)目的時(shí)候,需要初始化的全局實(shí)例更多家厌,并且顯得更加復(fù)雜播玖。
那么為了解決依賴相關(guān)的問(wèn)題,減少每個(gè)項(xiàng)目開啟時(shí)重復(fù)的樣板代碼構(gòu)建饭于,Dagger2就派上了用場(chǎng)蜀踏。
有一個(gè)用來(lái)解釋【依賴注入是什么】的最佳案例就是:ButterKnife
它是這樣用的:
public class MainActivity extends AppCompatActivity {
@BindView(R.id.button1) View button1;
@BindView(R.id.text1) View text1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
}
聲明依賴的組件维蒙,通過(guò)注解確定id,使用bind方法傳入this脓斩,完成依賴注入木西。
這就好像你告訴一個(gè)服務(wù)商,你需要什么随静,然后給出收貨地址八千,而服務(wù)商則生產(chǎn)出來(lái),逐一寄到提供的地址燎猛。
Dagger2的用法恋捆,也是上述的形式,唯一例外的是重绷,你將同時(shí)扮演消費(fèi)者和生產(chǎn)商沸停。
這里不考慮復(fù)雜的情況,從入門的角度來(lái)看昭卓,對(duì)于使用Dagger2實(shí)現(xiàn)依賴注入愤钾,很有必要。
二候醒、怎么使用Dagger2能颁?
Dagger2是谷歌forked from square/dagger的一個(gè)分支,谷歌Dagger2開源框架的介紹是:
A fast dependency injector for Android and Java.
對(duì)于其與square的歷史淵源倒淫,github上框架介紹已經(jīng)寫得非常清楚
——翻譯過(guò)來(lái)伙菊,大概是:
- 消除所有反射,提升運(yùn)行時(shí)性能
- 編譯時(shí)處理敌土,更快更好的構(gòu)建速度
其實(shí)我是從square官網(wǎng)上發(fā)現(xiàn)的Dagger镜硕,然后在這個(gè)框架的github上看到介紹說(shuō),項(xiàng)目已經(jīng)標(biāo)記為不再維護(hù)返干,推薦使用Dagger2兴枯;而另一方面,網(wǎng)上找到的關(guān)于Dagger的資料矩欠,要么無(wú)法解釋清楚為什么要用念恍,要么就是用起來(lái)特別繁瑣(還不如getInstance簡(jiǎn)單粗暴)。
因此轉(zhuǎn)向了Dagger2晚顷,并且在很長(zhǎng)的一段困惑期中,苦苦掙扎:
要用依賴注入嗎疗疟?真的要用嗎该默?為什么要用呢?用了有什么好處呀策彤?……
后來(lái)干脆自己建立demo栓袖,一步步把玩匣摘,其他資料都不再作為參考,只留下官方sample作為注解的學(xué)習(xí)裹刮。邁出這一步之后音榜,才終于發(fā)現(xiàn)Dagger2的神奇和便利。
1.打開你項(xiàng)目下的gradle文件捧弃,添加Dagger2項(xiàng)目的依賴管理
// 依賴注入框架
compile 'com.google.dagger:dagger:2.10'
annotationProcessor 'com.google.dagger:dagger-compiler:2.10'
PS:這個(gè)版本并非最新版赠叼,有需要的話,可以去官網(wǎng)依賴最新的版本违霞,這里為了穩(wěn)定性嘴办,將不做升級(jí)。
2.繼承Application創(chuàng)建RandallApp买鸽,然后開始構(gòu)建Dagger2部件和模型
使用javax的注解@Singleton標(biāo)記為單例涧郊,即所實(shí)現(xiàn)的類只存在一個(gè)實(shí)例:
import javax.inject.Singleton;
@Singleton
public interface AppComponent {
// add inject method
}
創(chuàng)建AppModule并依賴Application實(shí)例:
public final class AppModule {
private final Application application;
public AppModule(Application application) {
this.application = application;
}
@Provides @Singleton Application provideApplication() {
return application;
}
}
創(chuàng)建AndroidModule,因?yàn)槠渌蚣苓€沒有添加依賴眼五,所以這里用Android SDK中的SystemService舉例:
@Module
public final class AndroidModule {
@Provides @Singleton AudioManager provideAudioManager(Application application) {
return (AudioManager) application.getSystemService(Context.AUDIO_SERVICE);
}
@Provides @Singleton SensorManager provideSensorManager(Application application) {
return (SensorManager) application.getSystemService(Context.SENSOR_SERVICE);
}
@Provides @Singleton Sensor provideSensorAccelerometer(SensorManager sensorManager) {
return sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
}
@Provides @Singleton ConnectivityManager provideConnectivityManager(Application application) {
return (ConnectivityManager) application.getSystemService(Context.CONNECTIVITY_SERVICE);
}
}
簡(jiǎn)單說(shuō)明一下AndroidModule和AppModule的關(guān)系:
首先妆艘,AndroidModule是細(xì)節(jié)模型,事實(shí)上全部在AppModule中提供實(shí)例也沒有關(guān)系看幼,但為了明確功能和類型批旺,所以就有了AndroidModule。
可以理解為桌吃,AndroidModule就是AppModule的分身朱沃、子模型,只要通過(guò)這樣的語(yǔ)法就能導(dǎo)入:
@Module(includes = {
AndroidModule.class,
})
public final class AppModule {
...
}
@Module和@Provides都是Dagger2的注解茅诱。前者用于類注解逗物,標(biāo)記這個(gè)類是一個(gè)模型;后者則用于方法注解瑟俭,標(biāo)記返回的實(shí)例可以提供依賴翎卓。
這兩個(gè)注解,可以讓“服務(wù)商”知道自己有哪些物品可以生產(chǎn):
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
// add inject method
}
AppComponent接口有兩種形式的方法:
- 當(dāng)需要注入的依賴很多時(shí)摆寄,可以創(chuàng)建inject方法失暴,傳入需要被注入依賴的對(duì)象實(shí)例;
- 當(dāng)僅需要一個(gè)全局單例時(shí)微饥,可以創(chuàng)建返回對(duì)應(yīng)實(shí)例的方法逗扒。
如何抉擇,當(dāng)由具體需求所決定欠橘。
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {
// add inject method
void inject(LoginActivity activity);
// create return method
Picasso picasso();
}
完成Dagger2部件與模型的構(gòu)建后矩肩,你的項(xiàng)目結(jié)構(gòu)應(yīng)當(dāng)是這樣:
隨后,你應(yīng)該make一下工程肃续,使得Dagger2編譯出你所需要的接口實(shí)現(xiàn)類黍檩。
make完成后叉袍,沒有錯(cuò)誤的話,你可以在RandallApp中刽酱,重寫onCreate方法喳逛,然后輸入Dagger...就會(huì)發(fā)現(xiàn)已經(jīng)有了DaggerAppComponent這個(gè)編譯生成的類。
public class RandallApp extends Application {
@Override public void onCreate() {
super.onCreate();
DaggerAppComponent.builder().build();
}
}
可以看看DaggerAppComponent的一些細(xì)節(jié)棵里,其中可能存在一些困惑:
public final class DaggerAppComponent implements AppComponent {
private DaggerAppComponent(Builder builder) {
assert builder != null;
}
public static Builder builder() {
return new Builder();
}
public static AppComponent create() {
return new Builder().build();
}
public static final class Builder {
private Builder() {}
public AppComponent build() {
return new DaggerAppComponent(this);
}
/**
* @deprecated This module is declared, but an instance is not used in the component. This
* method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
*/
@Deprecated
public Builder appModule(AppModule appModule) {
Preconditions.checkNotNull(appModule);
return this;
}
/**
* @deprecated This module is declared, but an instance is not used in the component. This
* method is a no-op. For more, see https://google.github.io/dagger/unused-modules.
*/
@Deprecated
public Builder androidModule(AndroidModule androidModule) {
Preconditions.checkNotNull(androidModule);
return this;
}
}
}
為什么Module都被“過(guò)時(shí)”了呢润文?因?yàn)楫?dāng)前工程中,沒有任何地方發(fā)出依賴需求衍慎。
提供全局的部件實(shí)例
public class RandallApp extends Application {
private static AppComponent appcomponent;
@Override public void onCreate() {
super.onCreate();
appcomponent = DaggerAppComponent.builder().build();
}
public static AppComponent appComponent() {
return appcomponent;
}
}
使用部件實(shí)例注入實(shí)例
public class LoginActivity extends AppCompatActivity implements LoaderCallbacks<Cursor> {
...
// dependency injection
@Inject ConnectivityManager cm;
@Inject AudioManager am;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
RandallApp.appComponent().inject(this);
...
}
}
再make一下转唉,此時(shí)所有依賴已經(jīng)成功注入
public final class DaggerAppComponent implements AppComponent {
private Provider<Application> provideApplicationProvider;
private Provider<ConnectivityManager> provideConnectivityManagerProvider;
private Provider<AudioManager> provideAudioManagerProvider;
private MembersInjector<LoginActivity> loginActivityMembersInjector;
private DaggerAppComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.provideApplicationProvider =
DoubleCheck.provider(AppModule_ProvideApplicationFactory.create(builder.appModule));
this.provideConnectivityManagerProvider =
DoubleCheck.provider(
AndroidModule_ProvideConnectivityManagerFactory.create(
builder.androidModule, provideApplicationProvider));
this.provideAudioManagerProvider =
DoubleCheck.provider(
AndroidModule_ProvideAudioManagerFactory.create(
builder.androidModule, provideApplicationProvider));
this.loginActivityMembersInjector =
LoginActivity_MembersInjector.create(
provideConnectivityManagerProvider, provideAudioManagerProvider);
}
@Override
public void inject(LoginActivity loginActivity) {
loginActivityMembersInjector.injectMembers(loginActivity);
}
public static final class Builder {
private AppModule appModule;
private AndroidModule androidModule;
private Builder() {}
public AppComponent build() {
if (appModule == null) {
throw new IllegalStateException(AppModule.class.getCanonicalName() + " must be set");
}
if (androidModule == null) {
this.androidModule = new AndroidModule();
}
return new DaggerAppComponent(this);
}
public Builder appModule(AppModule appModule) {
this.appModule = Preconditions.checkNotNull(appModule);
return this;
}
public Builder androidModule(AndroidModule androidModule) {
this.androidModule = Preconditions.checkNotNull(androidModule);
return this;
}
}
}
看起來(lái)似乎有一個(gè)問(wèn)題,當(dāng)AppModule是null的時(shí)候稳捆,會(huì)拋出一個(gè)異常赠法。原因在于,AppModule是需要Application實(shí)例去創(chuàng)建乔夯,但是Application是Android在應(yīng)用打開時(shí)才被創(chuàng)建砖织,因此需要在Applicaion的onCreate方法中,構(gòu)建AppComponent時(shí)加入一個(gè)AppModule實(shí)例末荐。
public class RandallApp extends Application {
private static AppComponent appcomponent;
@Override public void onCreate() {
super.onCreate();
appcomponent = DaggerAppComponent.builder()
.appModule(new AppModule(this))
.build();
}
public static AppComponent appComponent() {
return appcomponent;
}
}
AndroidModule已經(jīng)自動(dòng)new出來(lái)實(shí)例侧纯,無(wú)需多費(fèi)功夫。
三甲脏、總結(jié)
這樣就完成了整個(gè)Dagger2的構(gòu)建工作眶熬,以后再有其他框架的類實(shí)例需要被依賴,只要建立對(duì)應(yīng)的Module類块请,使用provides標(biāo)記的方法提供對(duì)應(yīng)的類實(shí)例娜氏,并包括在AppModule中,然后通過(guò)AppComponent添加inject方法注入需求類實(shí)例即可墩新。
再說(shuō)一點(diǎn)贸弥,維護(hù)期間,如果想改變框架海渊,或者刪除框架绵疲,只需要在AppModule中注釋導(dǎo)入的對(duì)應(yīng)Module,然后在需求類實(shí)例中臣疑,將Inject的依賴注釋即可盔憨。
Dagger2的基本使用就到這里,后面開始建立基于DataBinding框架的MVVM設(shè)計(jì)模式讯沈。