Dagger 構(gòu)造函數(shù)注入和@Inject注入的差別

最近一直在研究MVVM框架的具體實(shí)現(xiàn),在這其中就遇到一個(gè)小問(wèn)題,就是在ViewModel中使用@Inject注解注入和使用構(gòu)造函數(shù)注入是有細(xì)小差別的,也給不知道的童鞋標(biāo)個(gè)重點(diǎn),以后遇到了也能夠迅速想到我的這個(gè)文章。

Dagger注入的兩種方式

這里簡(jiǎn)單的介紹下注入的兩種方式。

成員變量注入

所謂的成員變量注入其實(shí)就是在你想注入的成員變量上使用@Inject注解。那么當(dāng)你通過(guò)Dagger去提供當(dāng)前對(duì)象的時(shí)候,會(huì)去找到當(dāng)前類的成員變量注入器,類似于這種XXX_MembersInjector。然后調(diào)用這個(gè)注入器的對(duì)應(yīng)注入的方法,就實(shí)現(xiàn)了成員變量方式的注入。舉個(gè)例子:

public class MainViewModel extends ViewModel {


    @Inject
    String title;

    @Inject
    public MainViewModel() {
        Log.d("TAG", "MainViewModel: " + title);
    }

}

這種就是成員變量注入。

構(gòu)造函數(shù)注入

所謂的構(gòu)造函數(shù)注入就是通過(guò)構(gòu)造函數(shù)去將需要的數(shù)據(jù)注入到當(dāng)前的類中,似乎也不需要夠多的解釋,也舉個(gè)例子,用于之后的對(duì)比。

public class FragmentViewModle extends ViewModel {
    
    String title;
    
    @Inject
    FragmentViewModle(String title) {
        Log.d("TAG", "FragmentViewModle: " + title);
    }

}

這種的就是構(gòu)造函數(shù)注入,對(duì)比一下上面的成員變量注入,有沒(méi)有發(fā)現(xiàn)區(qū)別?

區(qū)別就是少寫(xiě)了個(gè)@Inject ~哈 ~哈 ~哈 ~哈 ,當(dāng)然不是,下面進(jìn)入正題。

兩種注入方式的細(xì)小差別

這兩種注入方式其實(shí)在平時(shí)的使用過(guò)程中是看不出有什么不一樣的,反正之前我也沒(méi)有注意過(guò)。今天就莫名奇妙的遇到注入對(duì)象總為NULL的情況。我個(gè)人習(xí)慣一直是寫(xiě)成員變量方式注入的,然后發(fā)現(xiàn)在構(gòu)造函數(shù)中用不了,之前也一直沒(méi)注意過(guò)這個(gè)問(wèn)題然后就研究了一下具體的是因?yàn)槭裁?,發(fā)現(xiàn)兩種方式還是有小差別的。

還是上面的例子,兩個(gè)ViewModel的構(gòu)造函數(shù)中,通過(guò)成員變量注入的是無(wú)法獲取到當(dāng)前值的,通過(guò)構(gòu)造函數(shù)注入的是可以的。這個(gè)是結(jié)論。下面說(shuō)為什么。

查看Dagger編譯過(guò)的源碼,我可以看到這幾個(gè)類

Dagger生成類.png

其中不是重點(diǎn)的我已經(jīng)給劃掉了,可以通過(guò)命名就知道是具體干嘛的,分別是兩個(gè)Model的工廠類和成員變量注入類。

下面看一下具體實(shí)現(xiàn):

MainViewModle

public final class MainViewModel_Factory implements Factory<MainViewModel> {
  private final Provider<String> titleProvider;

  public MainViewModel_Factory(Provider<String> titleProvider) {
    this.titleProvider = titleProvider;
  }

  @Override
  public MainViewModel get() {
    //獲得一個(gè)MainViewModel 實(shí)例
    MainViewModel instance = new MainViewModel();
    //使用對(duì)應(yīng)的成員變量注入器為其注入成員變量
    MainViewModel_MembersInjector.injectTitle(instance, titleProvider.get());
    return instance;
  }

  public static Factory<MainViewModel> create(Provider<String> titleProvider) {
    return new MainViewModel_Factory(titleProvider);
  }

  public static MainViewModel newMainViewModel() {
    return new MainViewModel();
  }
}

重點(diǎn)已經(jīng)用注釋標(biāo)上了,會(huì)看到是先創(chuàng)建實(shí)例,然后通過(guò)成員變量注入器在注入需要的數(shù)據(jù)的。這同時(shí)也說(shuō)明,使用成員變量的方式進(jìn)行注入的時(shí)候,在當(dāng)前類的構(gòu)造方法中是無(wú)法使用注入的數(shù)據(jù)的

FragmentViewModel

public final class FragmentViewModle_Factory implements Factory<FragmentViewModle> {
  private final Provider<String> titleProvider;

  public FragmentViewModle_Factory(Provider<String> titleProvider) {
    this.titleProvider = titleProvider;
  }

  @Override
  public FragmentViewModle get() {
    //在獲取實(shí)例的同時(shí)將需要的數(shù)據(jù)通過(guò)構(gòu)造函數(shù)傳遞
    return new FragmentViewModle(titleProvider.get());
  }

  public static Factory<FragmentViewModle> create(Provider<String> titleProvider) {
    return new FragmentViewModle_Factory(titleProvider);
  }

  public static FragmentViewModle newFragmentViewModle(String title) {
    return new FragmentViewModle(title);
  }
}

這里就是直接通過(guò)構(gòu)造函數(shù)將數(shù)據(jù)傳遞到當(dāng)前的類中,所以在構(gòu)造函數(shù)中是可以使用的。

總結(jié)

通過(guò)一個(gè)工作中的小問(wèn)題發(fā)現(xiàn),使用兩種注入方式的區(qū)別。不過(guò)總體上推薦還是使用成員變量注入的方式,要不使用構(gòu)造函數(shù)的方式,你還是得把傳入的數(shù)據(jù)變成成員變量。不過(guò)如果想要在構(gòu)造函數(shù)中使用的話,那么就得使用構(gòu)造函數(shù)注入的方式。所以總體上來(lái)說(shuō)的話。

如果想在構(gòu)造函數(shù)中使用需要的數(shù)據(jù),那就使用構(gòu)造函數(shù)注入的方式,其他的就全使用成員變量的方式就可以了。

小思考:如果使用構(gòu)造函數(shù)注入,那么成員變量上同時(shí)使用@Inject標(biāo)記的話會(huì)怎么樣?也就是說(shuō)兩種方式同時(shí)使用會(huì)怎么樣?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容