前言
在上一篇文章里Android開(kāi)發(fā)之Dagger2--Module&Component(三),主要分析了Dagger2注入過(guò)程,Module和Component各有什么作用,使用的例子也是很簡(jiǎn)單的。前面曾經(jīng)提到過(guò),Dagger2最適合在mvp模式中使用,那這位篇文章就是應(yīng)用在mvp模式中。對(duì)mvp模式不了解的可以參照 Android架構(gòu)--MVC、MVP、MVVM ,MVP模式--登錄,這一篇文章就是在第二篇文章的基礎(chǔ)上引入了Dager2。
廢話不說(shuō),直接上代碼 源碼傳送門(mén)
代碼
1 .View
mvp模式的view部分,我把它放在一個(gè)接口里面,當(dāng)然可以單獨(dú)為登錄模塊寫(xiě)一個(gè)View接口,考慮到每個(gè)界面有可能都會(huì)有個(gè)View接口,所以我把它們放在一個(gè)IView接口里,這樣可以減少接口文件的數(shù)量。
view的主要作用是
1.接收用戶請(qǐng)求,并把請(qǐng)求傳遞給Presenter層處理。
2.Presenter操作View層更新數(shù)據(jù)
- 對(duì)于登錄模塊來(lái)說(shuō),getUserName(),getPassWord()方法分別是接收用戶名和密碼的,屬于接收用戶請(qǐng)求部分,在Presenter里這兩個(gè)方法會(huì)被調(diào)用,實(shí)現(xiàn)將用戶請(qǐng)求傳遞給Presenter層。
- closeDispose(Disposable disposable),toOtherActivity()方法則是數(shù)據(jù)請(qǐng)求成功后,Presenter操作View層進(jìn)行數(shù)據(jù)更新
public class IView {
/**
* 登錄
*/
public interface ILoginView {
String getUserName();
String getPassWord();
void showToast(String content);
void closeDispose(Disposable disposable);
void showProgress();
void hideProgress();
void toOtherActivity();
}
}
ILoginView 接口里定義的方法,最終是要在View模塊實(shí)現(xiàn)的,不同于在傳統(tǒng)的MVC模式,在MVC模式里,Activity既是View層,又是Model層,在MVP里,Activity則完全充當(dāng)了View的角色。
所以在要Activity里實(shí)現(xiàn)ILoginView 接口。
public class LoginActivity extends BaseActivity implements IView.ILoginView {
}
2. Model
Model層的作用如下:
- 接受Presenter的請(qǐng)求進(jìn)行數(shù)據(jù)更新
- 更新完成后通知Presenter數(shù)據(jù)更新完畢,Presenter再去通知View進(jìn)行界面更新
很明顯,Model層就是數(shù)據(jù)請(qǐng)求的層。
我同樣所有的Model都放在IModel類里面,IModel文件里的一個(gè)接口就對(duì)應(yīng)著一個(gè)Model模塊的網(wǎng)絡(luò)請(qǐng)求方法,方便對(duì)醒目里的所有網(wǎng)絡(luò)請(qǐng)求進(jìn)行管理。
很明顯,登錄模塊的Model就只有一個(gè)請(qǐng)求登錄的方法,對(duì)于通知Presenter層數(shù)據(jù)更新完畢,則是通過(guò)接口回調(diào)的方式。
public class IModel {
/**
* 登錄
*/
public interface ILoginModel {
void login(LoginBody loginBody, MyCallBack<UserLoginBean> callBack); //登錄
}
}
通過(guò)接口回調(diào)通知Presenter數(shù)據(jù)已更新完畢。
public interface MyCallBack<T> {
void onSuccess(T response); //成功回調(diào)
void onError(String header,String message); //失敗回調(diào)
void onDispose(Disposable disposable); // 切斷上有發(fā)送事件
}
對(duì)于登錄模塊,要有登錄模塊的Model繼承自IModel里對(duì)應(yīng)的接口。
public class LoginModel implements IModel.ILoginModel {
/**
* 構(gòu)造方法
*
* @param
*/
@Override
public void login(LoginBody loginBody, final MyCallBack<UserLoginBean> callBack) {
JsNetworkService.getInstance().getIJsNetworkService()
.getLogin(loginBody)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<UserLoginBean>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Disposable mDisposable; //用于Activity銷毀時(shí)停止執(zhí)行
mDisposable = d;
callBack.onDispose(mDisposable);
}
@Override
public void onNext(@NonNull UserLoginBean userLoginBean) {
callBack.onSuccess(userLoginBean);
}
@Override
public void onError(@NonNull Throwable e) {
callBack.onError("Server Error", "服務(wù)器異常,請(qǐng)稍后再試");
}
@Override
public void onComplete() {
}
});
}
}
3.Presenter
Presenter層的作用:
- 操作Model進(jìn)行數(shù)據(jù)更新
- 操作View層進(jìn)行界面更新
Presenter層實(shí)際起到的是個(gè)類似的中介作用,所以在Presenter層里有對(duì)View和Model的引用。
public class LoginPresenter {
private IView.ILoginView mILoginView;
private LoginModel mLoginModel;
public LoginPresenter(IView.ILoginView iLoginView) {
this.mILoginView = iLoginView;
mLoginModel = new LoginModel();
}
/**
* 登錄
*/
public void login() {
mILoginView.showProgress();
LoginBody loginBody = new LoginBody(mILoginView.getPassWord(), mILoginView.getUserName());
mLoginModel.login(loginBody, new MyCallBack<UserLoginBean>() {
@Override
public void onSuccess(UserLoginBean userLoginBean) {
mILoginView.hideProgress();
if (userLoginBean.getStatus().equals("1")) {
mILoginView.toOtherActivity();
}
mILoginView.showToast(userLoginBean.getMessage());
}
@Override
public void onError(String header, String message) {
mILoginView.hideProgress();
mILoginView.showToast(message);
}
@Override
public void onDispose(Disposable disposable) {
mILoginView.closeDispose(disposable);
}
});
/* mLoginModel.login(loginBody, new MyCallBack.OnLoginListener() {
@Override
public void loginSuccess(UserLoginBean userLoginBean) {
mILoginView.showToast(userLoginBean.getMessage());
}
@Override
public void loginFailed(String header, String message) {
}
@Override
public void dispose(Disposable disposable) {
mILoginView.closeDispose(disposable);
}
});*/
}
}
然后再Activity里,通過(guò)下面的代碼引入
LoginPresenter mLoginPresenter = new LoginPresenter(this);
通過(guò) mLoginPresenter.login()在Activity里執(zhí)行登錄方法。
上面mvp模式時(shí)沒(méi)有引進(jìn)Dagger2的時(shí)候,下面引進(jìn)Dagger2。
1.首次分析一下需要Inject哪個(gè)對(duì)象。
- 在Activity里持有了一個(gè)LoginPresenter 對(duì)象的引用,傳入的是一個(gè)IView.ILoginView,通過(guò)IView.ILoginView,LoginPresenter 實(shí)現(xiàn)從Activity接接受請(qǐng)求,請(qǐng)求成功后通知Activity更新界面。所以這個(gè)LoginPresenter 可以通過(guò)Inject的形式注入。
LoginPresenter mLoginPresenter = new LoginPresenter(this);
- 在LoginPresenter里,構(gòu)造方法里有個(gè)LoginModel對(duì)象,所以也是可以注入的。
public LoginPresenter(IView.ILoginView iLoginView) {
this.mILoginView = iLoginView;
mLoginModel = new LoginModel();
}
所以LoginActivity里修改代碼如下:
@Inject
LoginPresenter mLoginPresenter;
LoginPresenter里修改代碼如下:
@Inject
LoginModel mLoginModel;
2. Module
前文說(shuō)過(guò),Module是提供依賴的,要提供@Provides注解的以provide開(kāi)頭的方法。
上面說(shuō)過(guò),我們需要提供的是LoginPresenter和LoginModel的對(duì)象。
但是在提供LoginPresenter對(duì)象的時(shí)候,發(fā)現(xiàn)它需要一個(gè)IView.ILoginView的對(duì)象,所以我們還要用過(guò)IView.ILoginView的對(duì)象。
所以這里我們要提供三個(gè)依賴。
在這里補(bǔ)充一下當(dāng)遇到@Inject注解的時(shí)候處理步驟:
1. 查找Module中是否有創(chuàng)建該類的方法
2. 若存在創(chuàng)建該類的方法,查看該方法是否有參數(shù)
2.1 有參數(shù),實(shí)例化該類,并且從 步驟1 開(kāi)始初始化每個(gè)參數(shù)
2.2 沒(méi)有參數(shù),直接實(shí)例化該類,一次注入完成
3. 不存在創(chuàng)建該類的方法,查找Inject注解的構(gòu)造函數(shù),看構(gòu)造函數(shù)是否存在參數(shù)
3.1:若存在參數(shù),則 步驟1 開(kāi)始依次初始化每個(gè)參數(shù)
3.2:若不存在參數(shù),則直接初始化該類實(shí)例,一次依賴注入完成0
所以Module的代碼為
@Module
public class LoginModule {
private IView.ILoginView loginView;
public LoginModule(){
}
public LoginModule(IView.ILoginView view){
this.loginView=view;
}
/**
* 提供LoginPresenter
* @param iLoginView
* @return
*/
@Provides
@Singleton
LoginPresenter provideLoginPresenter(IView.ILoginView iLoginView){
return new LoginPresenter(iLoginView);
}
@Provides
@Singleton
IView.ILoginView provideILoginView(){
return loginView;
}
@Provides
@Singleton
LoginModel provideLoginModel(){
return new LoginModel();
}
}
這里提一下,LoginModule有兩個(gè)構(gòu)造方法,因?yàn)樽⑷氲紸ctivity是需要參數(shù)的,而注入到LoginPresenter是不需要參數(shù)的。
3.Component
Component 是聯(lián)系inject和Module的橋梁,習(xí)慣稱為注入器
@Singleton
@Component(modules = {LoginModule.class})
public interface LoginComponent {
void inject(LoginActivity loginActivity);
void inject(LoginPresenter loginPresenter);
}
4.執(zhí)行注入
在Activity里添加代碼
DaggerLoginComponent.builder()
.loginModule(new LoginModule(this))
.build()
.inject(this);
在LoginPresenter里添加代碼
DaggerLoginComponent.builder()
.loginModule(new LoginModule())
.build()
.inject(this);
編譯執(zhí)行,即可看到效果

源碼傳送門(mén)
目前我們接觸到的Dagger2的注解符,有@Inject @Module @Provide @Component等,其實(shí)Dagger2還有其他的注解符,比如 @Singleton(其實(shí)前面代碼有了),@Scope @Qualifier等,下一篇文章簡(jiǎn)要介紹一下。