看了很多關(guān)于Dagger2的中文用法介紹,看過之后的感受一言難盡须眷。
這里是幾篇相對好一些的。
https://blog.csdn.net/mq2553299/article/details/77485800
http://www.reibang.com/p/65737ac39c44
http://www.reibang.com/p/22c397354997
下面的鏈接是一篇Dagger2英文android教學(xué)沟突,比大部分中文的要好很多花颗。(需要翻墻)
https://medium.com/@harivigneshjayapalan/dagger-2-for-android-beginners-introduction-be6580cb3edb
順便附上Dagger2的官網(wǎng)和代碼(包括example)以及google的官方demo
https://google.github.io/dagger/users-guide
https://github.com/google/dagger
https://github.com/googlesamples/android-architecture/tree/todo-mvp-dagger
簡單的說下思路
理解依賴注入(DI)
A類中有B類的對象,就叫A類依賴B類惠拭,B類是A類的依賴扩劝。
這里有兩個War類,他們有不同的構(gòu)造方法职辅。
public class War {
private Starks starks;
private Boltons boltons;
public War(){
starks = new Starks();
boltons = new Boltons();
starks.prepareForWar();
starks.reportForWar();
boltons.prepareForWar();
starks.reportForWar();
}
}
public class War {
private Starks starks;
private Boltons boltons;
//DI - getting dependencies from else where via constructor
public War(Starks starks, Boltons bolton){
this.starks = starks;
this.boltons = bolton;
}
public void prepare(){
starks.prepareForWar();
boltons.prepareForWar();
}
public void report(){
starks.reportForWar();
boltons.reportForWar();
}
}
對于第一種構(gòu)造方法棒呛,如果Starks和Boltons類的構(gòu)造方法發(fā)生變化,需要修改War類中的代碼域携,耦合嚴(yán)重簇秒。
對于第二種構(gòu)造模式,在實(shí)例化war對象時需要提供一個Starks對象和Boltons對象秀鞭,這個過程——將依賴注入的過程在程序的主方法中實(shí)現(xiàn)趋观。
public class BattleOfBastards {
public static void main(String[] args){
Starks starks = new Starks();
Boltons boltons = new Boltons();
War war = new War(starks,boltons);
war.prepare();
war.report();
}
}
在android開發(fā)過程中,這個過程在Activity的onCreate(Bundle savedInstanceState)方法和Application的onCreate()方法以及Fragment的onAttach(Context context)方法中實(shí)現(xiàn)锋边。
(該內(nèi)容來自英文教學(xué)皱坛,中文的我沒看到過)
(這是Activity和Fragment生命周期的第一個方法,避免出現(xiàn)對象為null的錯誤)
Dagger2的作用就是通過一系列工廠方法實(shí)例化依賴注入所需要的對象豆巨。
具體實(shí)現(xiàn)過程
建議查看英文教程
https://medium.com/@harivigneshjayapalan/dagger-2-for-android-beginners-introduction-be6580cb3edb
要記住Dagger2的實(shí)現(xiàn)思想——在實(shí)例化一個對象的時候?qū)⑺枰囊蕾囎⑷肫渲惺1佟_@里有三個基本問題,誰是依賴類往扔,被依賴的對象需要注入到哪里去贩猎,具體注入方式。重點(diǎn)就在于具體注入方式瓤球。
注意其編寫代碼的思路
1、Top @Component
2卦羡、@Module
3噪馏、連接Modules
4、關(guān)聯(lián)Component和Module
5绿饵、編譯和注入
這和Dagger2官網(wǎng)的User Guide中的思路基本相反
聲明依賴欠肾,滿足依賴,建立圖表
剩下的則是注意懶加載拟赊,單例和范圍限定符等常用注解刺桃。
關(guān)于接口和MVP模式
在MVP模式中,一般會有一個Contract接口吸祟,該接口中有Presenter和View兩個接口瑟慈,我們需要實(shí)現(xiàn)這兩個接口桃移,并分別在接口的實(shí)現(xiàn)類中調(diào)用另一個接口的方法。為了解耦在實(shí)現(xiàn)類中葛碧,我們聲明的是接口而不是實(shí)現(xiàn)類借杰。
我們先看Dagger2官方example中是如何聲明接口依賴的。
這個是第一種聲明方法(在構(gòu)造方法中使用了@Inject)进泼。Pump為接口蔗衡,PumpModule是Module類,Thermosiphon是接口的實(shí)現(xiàn)類乳绕。
interface Pump {
void pump();
}
@Module
abstract class PumpModule {
@Binds
abstract Pump providePump(Thermosiphon pump);
}
class Thermosiphon implements Pump {
private final Heater heater;
@Inject
Thermosiphon(Heater heater) {
this.heater = heater;
}
@Override public void pump() {
if (heater.isHot()) {
System.out.println("=> => pumping => =>");
}
}
}
在聲明的過程中绞惦,@Inject標(biāo)注了Thermosiphon類的構(gòu)造方法,抽象PumpModule類中用@Binds標(biāo)注了抽象方法providePump(Thermosiphon pump)洋措,該方法返回接口Pump济蝉。在最終的使用過程中該方法并沒有使用,該方法是用于編譯時生成代碼的綁定聲明呻纹。
這個是第二種聲明方法(使用Module類)堆生。
@Module(includes = PumpModule.class)
class DripCoffeeModule {
@Provides
@Singleton
Heater provideHeater() {
return new ElectricHeater();
}
}
class ElectricHeater implements Heater {
boolean heating;
@Override public void on() {
System.out.println("~ ~ ~ heating ~ ~ ~");
this.heating = true;
}
@Override public void off() {
this.heating = false;
}
@Override public boolean isHot() {
return heating;
}
}
interface Heater {
void on();
void off();
boolean isHot();
}
需要注意的就是DripCoffeeModule 類中唯一的方法,聲明的返回類型是接口雷酪,返回了一個新的ElectricHeater對象淑仆。
在谷歌的官方example中,Activity管理Fragment的生命周期哥力,F(xiàn)ragment用于展示數(shù)據(jù)蔗怠,Presenter被注入到了Fragment里,F(xiàn)ragment被注入到Activity中吩跋。官方example使用了Dagger-Android組件寞射,我們暫時先不管這個。以TaskDetail為例锌钮,可以看到TaskDetailPresenter的構(gòu)造方法被@Inject標(biāo)注桥温,這是第一種聲明方法。在TaskDetailPresenterModule 類中有抽象方法statitsticsPresenter(TaskDetailPresenter presenter)梁丘,這和之前提到的是一樣的侵浸。
final class TaskDetailPresenter implements TaskDetailContract.Presenter {
...
@Inject
TaskDetailPresenter(@Nullable String taskId,
TasksRepository tasksRepository) {
mTasksRepository = tasksRepository;
mTaskId = taskId;
}
...
}
@Module
public abstract class TaskDetailPresenterModule {
@FragmentScoped
@ContributesAndroidInjector
abstract TaskDetailFragment taskDetailFragment();
@ActivityScoped
@Binds
abstract TaskDetailContract.Presenter statitsticsPresenter(TaskDetailPresenter presenter);
@Provides
@ActivityScoped
static String provideTaskId(TaskDetailActivity activity) {
return activity.getIntent().getStringExtra(EXTRA_TASK_ID);
}
}
這里另外要注意的是statitsticsPresenter方法是被@ActivityScoped標(biāo)注的,這意味著它的生命周期應(yīng)該和Activity一致氛谜。