Dagger2是一款依賴注入框架,相比于黃油刀肠骆,Dagger2的入門難度系數(shù)更大算途。如果你還沒有使用過Dagger2,趕緊去嘗試一下吧蚀腿。
首先說一下Dagger2嘴瓤,可以幫我們干哪些活。使用過MVP開發(fā)的老鐵們都知道莉钙,Activity持有Presenter層的實例廓脆,也就是說 ,我們需要去實例化這個Presenter,而Presenter持有了View層接口的實例。這樣程序之間耦合性非常嚴(yán)重磁玉,我們希望停忿,把某個類的實例化過程放到一個容器中,當(dāng)前的Activity不需要去管理他的實例化過程蚊伞,說的直白點瞎嬉,不用我們手動的去new 這個對象了尉咕。我們仔細想想串前,這樣做有什么好處,假設(shè)程序中有很多的地方用到了這個Presenter曙旭,有朝一日别垮,我們發(fā)現(xiàn),Presenter設(shè)計的不夠完美便监,構(gòu)造方法需要改動,這樣一來可就麻煩了碳想,所有用到的Presenter的地方烧董,都需要去進行改動。這個時候胧奔,Dagger派上用場了
常規(guī)寫法:
public class MainActivity extends AppCompatActivity implements IView{
public MainPresenter mainPresenter;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.tv_1);
// 實例化Presenter
mainPresenter = new MainPresenter(this);
mainPresenter.getData();
}
@Override
public void getString(String str) {
// Iview 接口的回調(diào)
textView.setText(str);
}
}
public interface IView {
void getString(String str);
}
public class MainPresenter {
IView iView;
MainPresenter(IView iView) {
this.iView = iView;
}
// 提供給 Activity層調(diào)用
public void getData() {
// dosomething:假設(shè)通過Model層獲取到數(shù)據(jù)之后逊移,回調(diào)給IView。
iView.getString("hello java");
}
}
以上就是最簡單的MVP的寫法(沒有寫Model層)龙填。
使用Dagger怎么寫呢胳泉?
public class MainActivity extends AppCompatActivity implements IView{
@Inject
public MainPresenter mainPresenter;
private TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = findViewById(R.id.tv_1);
DaggerMainComponent.builder()
.mainViewModule(new MainViewModule(this))
.build()
.inject(this);
mainPresenter.getData();
}
@Override
public void getString(String str) {
// TODO
textView.setText(str);
}
}
public interface IView {
void getString(String str);
}
public class MainPresenter {
IView iView;
@Inject
MainPresenter(IView iView) {
this.iView = iView;
}
public void getData() {
// dosomething:假設(shè)通過Model層獲取到數(shù)據(jù)之后,回調(diào)給IView岩遗。
iView.getString("hello java");
}
}
相比于常規(guī)寫法扇商,我們沒有在MainActivity里進行new MainPresenter(this)操作,而是使用了 @Inject 來標(biāo)注了我們想要實例化的類以及標(biāo)注它的構(gòu)造函數(shù)宿礁。使用@Inject相當(dāng)于做了個"記號"案铺,告訴Dagger,我想要這個類的實例,麻煩你去幫我做一下實例化操作梆靖。
這里再貼一下控汉,Component和Module的代碼:
### MainComponent
@Component (modules = {MainViewModule.class})
public interface MainComponent {
void inject(MainActivity activity);
}
////////////////////////////////////////////
### MainViewModule
@Module
public class MainViewModule {
IView iView;
public MainViewModule(IView iView) {
this.iView = iView;
}
@Provides
IView create() {
return iView;
}
}
以上是Dagger2很簡單的使用笔诵,當(dāng)然這也不是我們今天所要關(guān)心的,今天的主題是姑子,Dagger2是怎么幫我們實現(xiàn)了 new MainPresenter(this) 這個操作的嗤放,內(nèi)部的邏輯是怎樣的呢?
簡單分析原理
Dagger2自動生成代碼的原理是 通過apt插件在編譯時期生成相應(yīng)的注入代碼,接下來我們就一個一個的分析壁酬。
1.MainPresenter與MainPresenter_Factory
我們用 @Inject 標(biāo)注了MainPresenter 以及他的 構(gòu)造函數(shù),然后我們Rebuild Project一下恨课,會在app/build/generated/source/apt/debug/包名/ 下生成一個 類 MainPresenter_Factory舆乔,這里貼一下 MainPresenter與MainPresenter_Factory 的代碼:
### MainPresenter_Factory類
public final class MainPresenter_Factory implements Factory<MainPresenter> {
private final Provider<IView> iViewProvider;
public MainPresenter_Factory(Provider<IView> iViewProvider) {
assert iViewProvider != null;
this.iViewProvider = iViewProvider;
}
@Override
public MainPresenter get() {
return new MainPresenter(iViewProvider.get());
}
public static Factory<MainPresenter> create(Provider<IView> iViewProvider) {
return new MainPresenter_Factory(iViewProvider);
}
}
### MainPresenter類
public class MainPresenter {
IView iView;
@Inject
MainPresenter(IView iView) {
this.iView = iView;
}
public void getData() {
// dosomething:假設(shè)通過Model層獲取到數(shù)據(jù)之后,回調(diào)給IView剂公。
iView.getString("hello java");
}
}
我們重點看MainPresenter_Factory 的get()方法希俩,返回類型是 MainPresenter,get()方法內(nèi)部實際上是去new了一個MainPresenter纲辽,傳入的參數(shù)是iViewProvider.get()颜武。我們不禁會想,Dagger2 是不是在這里幫我們實例化MainPresenter的拖吼?答案是肯定的
iViewProvider是一個Provider類型鳞上,泛型參數(shù)是我們 new MainPresenter()所需要的IView。iViewProvider是在MainPresenter_Factory 的構(gòu)造函數(shù)進行初始化的吊档。
public interface Provider<T> {
T get();
}
create()返回返回一個 MainPresenter_Factory實例篙议,好像沒什么好說的,暫時先放一邊怠硼。
MainPresenter_Factory類看完了鬼贱,還是一頭霧水,我們知道get()方法會返回一個我們所需要的MainPresenter實例香璃,但是我們不清楚 get()是被誰調(diào)用的这难,以及iViewProvider.get() 是誰提供的呢?葡秒?
思考: MainPresenter 的構(gòu)造函數(shù)中傳入的參數(shù)是IView姻乓,而IView是接口類型,Dagger明確規(guī)定眯牧,不能使用@Inject來標(biāo)注接口和第三方庫糖权,碰到這種情況,需要使用到Module炸站,所以我們有理由相信星澳,iViewProvider.get() 是由MainViewModule提供的
帶著這兩個疑問看下文!旱易!!
2.MainViewModule與MainViewModule_CreateFactory
public final class MainViewModule_CreateFactory implements Factory<IView> {
private final MainViewModule module;
public MainViewModule_CreateFactory(MainViewModule module) {
assert module != null;
this.module = module;
}
@Override
public IView get() {
IView provided = module.create();
if (provided == null) {
throw new NullPointerException("Cannot return null from a non-@Nullable @Provides method");
}
return provided;
}
public static Factory<IView> create(MainViewModule module) {
return new MainViewModule_CreateFactory(module);
}
}
////////////////////////////////////////////
@Module
public class MainViewModule {
IView iView;
public MainViewModule(IView iView) {
this.iView = iView;
}
@Provides
IView create() {
return iView;
}
}
重點看看 MainViewModule_CreateFactory的get()方法禁偎,返回IView,這不就是我們new MainPresenter()所需要的參數(shù)嗎腿堤!但是到這里我們還是不能確定,iViewProvider.get() 是由MainViewModule提供的如暖!
我們雖然找到了MainViewModule_CreateFactory笆檀,也看到了它的get()方法的返回值就是我們 new MainPresenter()所需要的那個參數(shù),但是盒至,我們沒有找到證據(jù)酗洒,iViewProvider.get() 就是由MainViewModule提供的。
正當(dāng)我一籌莫展的時候枷遂,想起了之前網(wǎng)上看博客大牛們說樱衷,Component的作用像一個橋梁,負(fù)責(zé)把@Inject和Module的提供的實例一起注入到目標(biāo)類中.. 莫非酒唉,我要找的答案在MainComponent以及它生成的類中嗎矩桂?
答案也是肯定的!;韭住侄榴!
3.MainComponent與DaggerMainComponent
public final class DaggerMainComponent implements MainComponent {
private Provider<IView> createProvider;
private Provider<MainPresenter> mainPresenterProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private DaggerMainComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
private void initialize(final Builder builder) {
this.createProvider = MainViewModule_CreateFactory.create(builder.mainViewModule);
this.mainPresenterProvider = MainPresenter_Factory.create(createProvider);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create((MembersInjector) MembersInjectors.noOp(), mainPresenterProvider);
}
@Override
public void inject(MainActivity activity) {
mainActivityMembersInjector.injectMembers(activity);
}
public static final class Builder {
private MainViewModule mainViewModule;
private Builder() {
}
public MainComponent build() {
if (mainViewModule == null) {
throw new IllegalStateException("mainViewModule must be set");
}
return new DaggerMainComponent(this);
}
public Builder mainViewModule(MainViewModule mainViewModule) {
if (mainViewModule == null) {
throw new NullPointerException("mainViewModule");
}
this.mainViewModule = mainViewModule;
return this;
}
}
}
//////////////////////////////////
@Component (modules = {MainViewModule.class})
public interface MainComponent {
void inject(MainActivity activity);
}
DaggerMainComponent實現(xiàn)了MainComponent接口。在構(gòu)造函數(shù)里調(diào)用了initialize()网沾,initialize()內(nèi)部做了初始化操作癞蚕。首先創(chuàng)造了MainViewModule_CreateFactory實例,接著把這個實例作為參數(shù)去生成MainPresenter_Factory實例辉哥,這不就是我們在第二步一直困惑的地方嗎涣达,終于找到證據(jù)了,哈哈。 MainPresent實例所需要的依賴由MainViewModule_CreateFactory提供证薇。最后一步是生成MainActivity_MembersInjector實例度苔,我猜測是MainActivity的注入類。
內(nèi)部類Builder主要是做了創(chuàng)建Module以及自身的實例浑度,不是重點寇窑。
我們大概捋一捋,我們所需要的MainPresenter實例由MainPresenter_Factory##get()創(chuàng)建箩张,而創(chuàng)建MainPresent實例所需要的依賴由MainViewModule_CreateFactory提供甩骏。但是,在步驟1里先慷,我們還是有個疑問沒解決饮笛,MainPresenter_Factory##get()是被誰調(diào)用的呢?
重點看看DaggerMainComponent###inject()方法论熙,方法內(nèi)部調(diào)用的是 mainActivityMembersInjector.injectMembers(activity)福青,將MainActivity注入到MainActivity_MembersInjector類中。
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final MembersInjector<AppCompatActivity> supertypeInjector;
private final Provider<MainPresenter> mainPresenterProvider;
public MainActivity_MembersInjector(MembersInjector<AppCompatActivity> supertypeInjector, Provider<MainPresenter> mainPresenterProvider) {
assert supertypeInjector != null;
this.supertypeInjector = supertypeInjector;
assert mainPresenterProvider != null;
this.mainPresenterProvider = mainPresenterProvider;
}
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.mainPresenter = mainPresenterProvider.get();
}
public static MembersInjector<MainActivity> create(MembersInjector<AppCompatActivity> supertypeInjector, Provider<MainPresenter> mainPresenterProvider) {
return new MainActivity_MembersInjector(supertypeInjector, mainPresenterProvider);
}
}
MainActivity_MembersInjector構(gòu)造函數(shù)里接收一個Provider<MainPresenter>參數(shù),這個在injectMembers()里會用到无午。
我們單獨把injectMembers()拎出來:
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
supertypeInjector.injectMembers(instance);
instance.mainPresenter = mainPresenterProvider.get();
}
instance.mainPresenter = mainPresenterProvider.get();
看到這行代碼的時候媒役,所有的疑問都消除了,也就是說 上面的那個疑問:MainPresenter_Factory##get()是被誰調(diào)用的呢宪迟?酣衷? 它其實是在這里被調(diào)用的。
看到這里是不是有種 恍然大悟的感覺次泽!mainPresenterProvider.get()也就是 Dagger2幫助我們生成的MainPresenter實例穿仪,剛開始我們還保持懷疑,mainPresenterProvider.get()得到到實例是不是指向了我們MainActivity的那個實例呢意荤? 看到這里啊片,才真正的明白了,將MainPresenter_Factory中創(chuàng)建好的MainPresenter實例賦值給instance(MainActivity)的成員mainPresenter袭异,這樣我們用@Inject標(biāo)注的mainPresenter就得到了實例化。
做個小結(jié)吧炬藤,Module的作用是 提供依賴御铃,像我們的例子中的:
MainPresenter(IView iView) {
this.iView = iView;
}
這個IView 實例就是由Module去提供的,而Component的作用像一個橋梁沈矿,負(fù)責(zé)把@Inject和Module的提供的實例一起注入到目標(biāo)類中上真,像這個例子,目標(biāo)類就是MainActivity了羹膳。