最近一直在研究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è)類

其中不是重點(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ì)怎么樣?