依賴
如果 Class A 中有 Class B 的一個實例,那么可以說 Class A 對 Class B 有一個依賴。比如下面類 Home 中用到一個 Father 對象,我們就說 Home 對 Father 有一個依賴。
public class Home {
...
Father father;
...
public Home() {
father = new Father();
}
}
這段代碼存在的問題:
1、如果現(xiàn)在要修改Father對象的生成方式,如需要通過new Father(String Name)來實例化Father,那就也要修改Home的代碼;
2、想測試不同F(xiàn)ather對象對Home的影響很困難,因為father的初始化被寫死在Human的構(gòu)造函數(shù)中;
3、如果new Father()過程非常緩慢,單測時我們希望用已經(jīng)初始化好的 father 對象 Mock 掉這個過程也很困難。
這種在一個類中直接創(chuàng)建另一個類的對象的代碼,被稱為硬初始化(Hard init),和硬編碼(hard-coded strings)以及硬編碼的數(shù)字(magic numbers)一樣,是一種導(dǎo)致耦合的壞味道。
依賴注入
public class Home {
...
Father father;
...
public Home(Father father) {
this.father = father;
}
}
像上面這種不是自己主動初始化依賴,而通過外部傳來依賴的方式,就稱為依賴注入。
下面是幾種實現(xiàn)依賴注入的方式:
構(gòu)造函數(shù)注入
public class Home {
...
Father father;
...
public Home(Father father) {
this.father = father;
}
}
這應(yīng)該是最簡單的依賴注入方式。Father對象在Home類之外創(chuàng)建,再傳進來。
setter注入
public class Home {
...
Father father;
...
public void setFather(Father father) {
this.father = father;
}
}
接口注入
創(chuàng)建一個接口
public interface InjectFather {
void injectFather(Father father);
}
實現(xiàn)這個接口
class Home implements InjectFather {
...
public void InjectFather (Father father) {
this.father = father;
}
...
}
在Java中實現(xiàn)依賴注入
在Java中實現(xiàn)依賴注入除了以上說的幾種,還有一種最常用的是使用注解。
public class Home {
...
@Inject
Father father;
...
public Home() {
}
這種方式需要使用依賴注入框架,并進行簡單的配置?,F(xiàn)在 Java 語言中較流行的依賴注入框架有 Google Guice、Spring 等,而在 Android 上比較流行的有 RoboGuice、Dagger 等。
Dagger
Dagger是為Android和Java平臺提供的一個完全靜態(tài)的,在編譯時進行依賴注入的框架,原來是由Square公司維護,現(xiàn)在由Google維護。 Dagger就是用來創(chuàng)造一個容器,所有需要被依賴的對象在Dagger的容器中實例化,并通過Dagger注入到合適的地方。
Dagger的基本使用
通常情況下引用一個類的做法
先定義一個簡單的類
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在另一個類中對其引用
public class Activity{
private void initData() {
User user = new User();
user.setName("測試");
}
}
Dagger2的做法
首先在被依賴類的構(gòu)造函數(shù)用@Inject標注
public class User {
private String name;
@Inject
public User() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
創(chuàng)建一個@Component標注的注入器接口,并在注入器中使用 void inject(MainActivity MainActivity);來表明哪里要用到注入器
@Component
public interface ActivityComponent {
void inject(MainActivity MainActivity);
}
在MainActivity中對注入器進行初始化DaggerActivityComponent.builder().build().inject(this); 初始化后該注入器就可以正常使用了;在MainActivity中對需要注入的類 User用@Inject進行標注,表示該類需要被注入,即實例化
public class Activity{
@Inject
User user;
private void initData() {
//DaggerActivityComponent是注入器是在編譯的過程中生成的
DaggerActivityComponent.builder().build().inject(this);
user.setName("測試");
}
}
- @Inject 主要有兩個作用,一個是使用在構(gòu)造函數(shù)上,通過標記構(gòu)造函數(shù)讓Dagger2來使用從而提供依賴,另一個作用就是標記在需要依賴的變量讓Dagger2為其提供依賴。
- @Component 一般用來標注接口,被標注了Component的接口在編譯時會產(chǎn)生相應(yīng)的類的實例來作為提供依賴方和需要依賴方之間的橋梁,把相關(guān)依賴注入到其中。
@Module和@Provide
@Inject是對類的構(gòu)造函數(shù)進行標注來進行實例化的,但是有些類,比如第三方OkHttpClient,我們是無法對其源碼進行修改的即對其構(gòu)造函數(shù)進行標注,這個時候我們就用到了@Module。
@Module是和@Component配合使用的,意思就是告訴注入器,如果你在實例化對象的時候,沒有找到合適的構(gòu)造函數(shù),你就來我這里找,@Module通常標注一個類,該類里面可以實例化各種類,Component在注入對象的時候先去Module中找,如果找不到就會檢查所有被@Inject標注的構(gòu)造函數(shù)
@Module
public class ActivityMoudle {
@Provides
@Singleton
OkHttpClient provideOkHttpClient() {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
Interceptor apikey = chain -> chain.proceed(chain.request().newBuilder()
.addHeader("apikey", Constants.Api_Key).build());
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(Constants.HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
.connectTimeout(Constants.HTTP_CONNECT_TIMEOUT, TimeUnit.MILLISECONDS)
.addInterceptor(apikey)
.addInterceptor(loggingInterceptor)
.build();
return okHttpClient;
}
}
- @Provide 用來標注一個方法,告訴注入器,我標注的方法你可以用來提供實例;
修改注入器
@Singleton
@Component(modules = ActivityMoudle.class)
public interface ActivityComponent {
void inject(MainActivity MainActivity);
}
Dagger原理淺析
我們先新建三個類,這三個類的內(nèi)容和上面的一致:

我們看DaggerActivityComponent的內(nèi)容,其實就是實現(xiàn)了我們定義的ActivityComponent接口:
package com.hochan.myapplication;
import dagger.MembersInjector;
import dagger.internal.MembersInjectors;
import javax.annotation.Generated;
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class DaggerActivityComponent implements ActivityComponent {
private MembersInjector<MainActivity> mainActivityMembersInjector;
private DaggerActivityComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static ActivityComponent create() {
return builder().build();
}
private void initialize(final Builder builder) {
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), User_Factory.create());
}
@Override
public void myInject(MainActivity activity) {
mainActivityMembersInjector.injectMembers(activity);
}
public static final class Builder {
private Builder() {
}
public ActivityComponent build() {
return new DaggerActivityComponent(this);
}
}
}
可以看到我們在接口中定義的myInject()方法:
@Override
public void myInject(MainActivity activity) {
mainActivityMembersInjector.injectMembers(activity);
}
就是在這個方法中把變量注入到Mainactivity中。
再看mainActivityMembersInjector這個變量,其實就是一個MembersInjector接口,其初始化在initialize()中完成:
private void initialize(final Builder builder) {
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), User_Factory.create());
}
而MainActivity_MembersInjector就是生成的另外一個類,這個類就是一個注入器。有多少個類依賴了其他的類,就有多少個這樣的注入器類生成。在這個類的injectMembers()方法中完成了對象的注入:
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.mUser = mUserProvider.get();
}
還有一個編譯之后生成的類User_Factory,就是一個對象的提供者。
@Generated("dagger.internal.codegen.ComponentProcessor")
public enum User_Factory implements Factory<User> {
INSTANCE;
@Override
public User get() {
return new User();
}
public static Factory<User> create() {
return INSTANCE;
}
}
這里User的構(gòu)造函數(shù)是沒有參數(shù)的,我們把它改成有參數(shù)再編譯看會變成什么:
@Inject
public User(String name){
}
編譯之后報錯,User_Factory多了一個參數(shù)nameProvider:
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class User_Factory implements Factory<User> {
private final Provider<String> nameProvider;
public User_Factory(Provider<String> nameProvider) {
assert nameProvider != null;
this.nameProvider = nameProvider;
}
@Override
public User get() {
return new User(nameProvider.get());
}
public static Factory<User> create(Provider<String> nameProvider) {
return new User_Factory(nameProvider);
}
}
get()函數(shù)變成了:
@Override
public User get() {
return new User(nameProvider.get());
}
而在DaggerActivityComponent中的初始化并沒有把這個參數(shù)傳進來:
從上面的介紹我們可以知道,可以通過module來讓Dagger找到獲取實例的方法。這里我們新建一個module來讓Dagger獲得初始化User要用到的name字符串:
@Module
public class ActivityModule {
@Provides
String myName(){
return "names";
}
}
然后在ActivityComponent中聲明這個類:
@Component(modules = ActivityModule.class)
public interface ActivityComponent {
void myInject(MainActivity activity);
}
之后就運行通過了,我們會發(fā)現(xiàn)編譯之后又多了一個類:ActivityModule_MyNameFactory
@Generated("dagger.internal.codegen.ComponentProcessor")
public final class ActivityModule_MyNameFactory implements Factory<String> {
private final ActivityModule module;
public ActivityModule_MyNameFactory(ActivityModule module) {
assert module != null;
this.module = module;
}
@Override
public String get() {
String provided = module.myName();
if (provided == null) {
throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
}
return provided;
}
public static Factory<String> create(ActivityModule module) {
return new ActivityModule_MyNameFactory(module);
}
}
在get()方法里通過ActivityModule調(diào)用定義好的方法來獲取到name的值。這里定位那個函數(shù)是獲取name的函數(shù)應(yīng)該是通過返回的類型來判斷的,因為如果在ActivityModule中有多個返回String的函數(shù)就會報錯。