注入神器Dagger2-----基本使用及原理分析(一)

Dagger2是一個實現注入的框架,相信大家都聽說過ButterKnife,Dagger2和ButterKnife的作用是一樣的,但是實現的功能更加強大。ButterKnife只能注入View和事件,而Dagger2可以注入任何一個對象。本節主要介紹一下Dagger2的實用及實現的原理。

一、Dagger2的使用

首先我先用張圖來簡單說明一下Dagger2使用的流程

圖中的Module是應用中常用的功能模塊,比如說網絡訪問,數據存儲等。這個類會有一個@Module的註解,具體的代碼我會在後面詳細介紹。其實這個Module的作用是提供各種功能對象,而這些Module會放到一個有@Component的容器類中,也就是圖中Component類。當我們想使用各種功能對象進行業務操作的時候,只需要這個容器就能得到被註冊了的功能對象,圖中的意思是在Activity中使用對象進行業務操作,當然也不僅限於Activity。

上圖相對來說還是太簡略了,並沒有完整的表達出Dagger2的原理,下面我們直接從代碼中感受一個Dagger2的強大。

1.引入Dagger2

implementation 'com.google.dagger:dagger:2.4'
annotationProcessor 'com.google.dagger:dagger-compiler:2.4'

2.創建網絡訪問對象及其Module模塊

首先創建一個HttpObject,我們假設這個HttpObject中有各種網絡的操作,get,post,put等

public void get(){
        Log.i("Dagger2","這裏是get方法");
    }
    
    public void post(){
        Log.i("Dagger2","這裏是post方法");
    }
}

創建HttpModule

@Module
public class HttpModule {
    @Provides
    public HttpObject providerHttpObject(){
        return new HttpObject();
    }
}

HttpModule的兩個註解是需要注意的地方:@Module這個註解相當於給當前類打了一個標記,表明了這個類的類型,便於注入到容器中;@Provides這個註解放在了方法的上面,從上面的代碼可以看出來,主要就是創建功能對象。

3.創建容器Component

@Component(modules = {HttpModule.class})
public interface MyComponent {
    void injectMainActivity(MainActivity mainActivity);
}

容器這個類被@Component所註解,而且是一個接口類,@Component中的modules參數接收的類型是一個數組,表示被裝入容器的Module有哪些。injectMainActivity方法表示這個容器中的功能對象(例如HttpObject)會在哪個類使用,我這裏使用的MainActivity做的測試,所以參數寫的是MainActivity。

4.在類中使用HttpObject

在配置完上述的代碼之後,一定先rebuild!

public class MainActivity extends AppCompatActivity {
    @Inject
    HttpObject mHttpObject;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerMyComponent.create().injectMainActivity(this);
        mHttpObject.get();
        mHttpObject.post();
    }
}

因爲我們要使用的類是HttpObject,所以在MainActivity創建這個類的對象,然後被@Inject所註解。要注意的是DaggerMyComponent這個類是rebuild之後生成的,調用DaggerMyComponent.create().inkectMainActivity(this)這句話來生成mHttpObject對象,調用HttpObject中的get和post方法就會有相應的輸出。

Dagger的優點

有的小夥伴會問,你整這麼一大堆是爲了啥?要不然直接創建對象,要不然創建一個單例,多省事,可比Dagger2的這種方式方便多了。在中大型項目中,類似於HttpObject這種對象會被大量的應用,如果突然有一天這個類的初始化方法改變了,你豈不是要修改每一處嗎。即便是使用單例getInstance方法也避免不了這種問題,因爲如果在創建對象的時候需要在構造器中添加一個參數,每一處的getInstance也需要被修改。而Dagger2完美的避免了這種問題

二、源碼分析

下面我們從源碼中分析Dagger2的實現流程

上面的代碼我們使用了create方法來創建MyComponent,這次我們使用建造者的方式來創建,Dagger2中提供了這種方式,如下代碼

DaggerMyComponent
                .builder()
                .httpModule(new HttpModule())
                .build()
                .injectMainActivity(this);

其實我們從create的方法中進入就可以看到,其實create中包裝了建造者的方式。

builder方法其實沒什麼說的,點進去看,其實就是Builder的創建,代碼我就不貼出來了。

httpModule這個方法肯定就是相應Module的創建了,代碼如下,我們可以看出來,源代碼中只是做了一個對象非空的檢查

public Builder httpModule(HttpModule httpModule) {
      this.httpModule = Preconditions.checkNotNull(httpModule);
      return this;
}

而build方法主要就DaggerMyComponent的創建,代碼如下:

public MyComponent build() {
      if (httpModule == null) {
        this.httpModule = new HttpModule();
      }
      return new DaggerMyComponent(this);
}

以上的代碼都沒什麼特別的,主要就是建造者模式的只用,下面我們來分析一下injectMainActivity方法的邏輯。

我們點擊進入injectMainActivity這個方法,會進入到我們所寫的MyComponent這個接口方法中,點擊圖中紅框的位置會出現接口的實現類或者直接進入到實現類

MyComponent的實現類其實我們已經見到了,就是DaggerMyComponent,其中injectMainActivity的實現方法如下:

@Override
  public void injectMainActivity(MainActivity mainActivity) {
    mainActivityMembersInjector.injectMembers(mainActivity);
  }

mainActivityMembersInjector的類是MembersInjector<T>這個接口類,同樣的我們查看這個方法的實現類方法:

我們發現實現類有兩個,那我們查看哪個呢?我們來這樣看:首先將項目切換到project模式,依次進入如下目錄:app->build->generated->source->apt->debug,到這裏,我們就發現了我們項目的包,可以看見生成了幾個類,如圖:

而圖中紅框標註的正是MembersInjector<T>的實現類,我們想要找的就是它,我們來查看injectMembers方法的實現:

 private final Provider<HttpObject> mHttpObjectProvider;

 @Override
  public void injectMembers(MainActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.mHttpObject = mHttpObjectProvider.get();
  }

代碼中的instance是MainActivity,而mHttpObject是MainActivity中的mHttpObject(從這裏我們可以看出來,想要被註解的對象修飾符一定是public),mHttpObject是通過mHttpObjectProvider.get()獲得的,mHttpObjectProvider的類是Provider,而Provider是一個接口,我們如果還是使用上面的方法來找實現類,你會發現實現類有四五十個,那怎麼辦呢?

從上面系統幫我們生成的類中有如下這麼一個類,而這個類這是我們想要找的Provider的實現類,我們點擊去查看get方法的實現:

@Override
  public HttpObject get() {
    return Preconditions.checkNotNull(
        module.providerHttpObject(), "Cannot return null from a non-@Nullable @Provides method");
  }

get方法所返回的是module通過providerHttpObject方法創建的,這個module是HttpModule,點擊去查看providerHttpObject:

@Module
public class HttpModule {
    @Provides
    public HttpObject providerHttpObject(){
        return new HttpObject();
    }
}

這個不就是我們的HttpModule中的方法嗎?是的,Dagger框架繞了一大圈創建了HttpObject這個對象。

以上就是Dagger創建對象的流程

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