mvp話說也出來好久了,初入學習Dagger的時候,就感受和mvp結合能更加有效的解決presenter注入的的問題,避免更多的代碼複寫!並且大概看了下網絡上的資源,通常可能是分開講解dagger和mvp技術,結合使用的不多,因此決定寫出來和你們一塊兒學習!html
MVP,全稱 Model-View-Presenter,要說MVP那就不得不說一說它的前輩MVC。
MVC(Model-View-Controller,模型-視圖-控制器)模式是80年代Smalltalk-80出現的一種軟件設計模式,後來獲得了普遍的應用,其主要目的在於促進應用中模型,視圖,控制器間的關注的清晰分離。MVP(Model-View-Presenter,模型-視圖-表示器)模式則是由IBM開發出來的一個針對C++和Java的編程模型,大概出現於2000年,是MVC模式的一個變種,主要用來隔離UI、UI邏輯和業務邏輯、數據。也就是說,MVP 是從經典的模式MVC演變而來,它們的基本思想有相通的地方:Controller/Presenter負責邏輯的處理,Model提供數據,View負責顯示,全部通訊都是單向的;java
MVP 模式將 Controller 更名爲 Presenter,同時改變了通訊方向git
一、各部分之間的通訊,都是雙向的。github
二、View 與 Model 不發生聯繫,都經過 Presenter 傳遞。編程
三、 View 很是薄,不部署任何業務邏輯,稱爲"被動視圖"(Passive View),即沒有任何主動性,而 Presenter很是厚,全部邏輯都部署在那裏。設計模式
所以咱們能夠發現MVP的優勢以下:網絡
一、模型與視圖徹底分離,咱們能夠修改視圖而不影響模型;ide
二、能夠更高效地使用模型,由於全部的交互都發生在一個地方——Presenter內部;單元測試
三、咱們能夠將一個Presenter用於多個視圖,而不須要改變Presenter的邏輯。這個特性很是的有用,由於視圖的變化老是比模型的變化頻繁;學習
四、若是咱們把邏輯放在Presenter中,那麼咱們就能夠脫離用戶接口來測試這些邏輯(單元測試)。
具體到Android App中,通常能夠將App根據程序的結構進行縱向劃分,根據MVP能夠將App分別爲模型層(M),UI層(V)和邏輯層(P)。
UI層通常包括Activity,Fragment,Adapter等直接和UI相關的類,UI層的Activity在啓動以後實例化相應的Presenter,App的控制權後移,由UI轉移到Presenter,二者之間的通訊經過BroadCast、Handler或者接口完成,只傳遞事件和結果。
舉個簡單的例子,UI層通知邏輯層(Presenter)用戶點擊了一個Button,邏輯層(Presenter)本身決定應該用什麼行爲進行響應,該找哪一個模型(Model)去作這件事,最後邏輯層(Presenter)將完成的結果更新到UI層
如何把mvp實如今咱們的代碼上呢?
能夠從上面簡單的demo的結構上看出,model和ui層都是提供了一個外部接口類,而presenter擁有這兩個類的依賴,而MvpActivity擁有presenter的依賴,當MvpActivity觸發事件後經過presenter觸發事件處理model,當model處理完成之後經過ui外部接口類回調給activity!
定義事件方法
public interface MvpUiImpl {
void showTest(String msg);
}複製代碼
public class MvpActivity extends AppCompatActivity implements MvpUiImpl{
MvpPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.testDoS();
}
});
}
@Override
public void showTest(String msg) {
TextView tv=(TextView)findViewById(R.id.tv);
tv.setText(msg);
}
}複製代碼
model接口定義處理數據方法
public interface MvpModelImpl {
MvpEntity test();
}複製代碼
實現具體的數據處理方法
public class MvpModel implements MvpModelImpl{
@Override
public MvpEntity test() {
return new MvpEntity("數據");
}
}複製代碼
經過ui和model對象的引用對象,事件觸發後調用數據model處理方法,成功後回調給ui界面
public class MvpPresenter {
MvpUiImpl ui;
MvpModelImpl model;
public MvpPresenter(MvpUiImpl ui, MvpModelImpl model) {
this.ui = ui;
this.model = model;
}
public void testDoS() {
MvpEntity entity = model.test();
ui.showTest(entity.getMsg());
}
}複製代碼
經過上面簡單的構建,到這裏一個傳統的mvp構建就算是完成了!可是 MvpPresenter類初始化須要傳遞的兩個依賴對象,這裏正好咱們可使用dagger2的依賴注入實現MvpPresenter,減小程序的耦合度!
Dagger在mvp中的運用主要是優化Presenter建立依賴對象,因此開始咱們的優化!
既然須要獲得一個Presenter,首先須要構建一個對應的module
@PerApp
@Module
public class MvpPresenterModule {
private MvpActivity activity;
public MvpPresenterModule(MvpActivity activity) {
this.activity = activity;
}
@Provides
MvpActivity provideActivity(){
return activity;
}
@Provides
MvpPresenter providePresenter(MvpActivity ui,MvpModel mvpModel){
return new MvpPresenter(ui,mvpModel);
}
@Provides
MvpModel provideMvpModel(){
return new MvpModel();
}
}複製代碼
注意:看完這段代碼估計有同窗發現,和以前的model構建好像不同呀,對!這裏咱們在MvpPresenterModule 中首先提供了兩個@Provides定義的方法,一個方法提供了MvpActivity ,另外一個提供了一個MvpModel 對象;而這兩個不正式初始MvpPresenter的依賴注入對象嘛!
是的這裏咱們經過dagger自帶的@Provides方法,首先提供了兩個MvpPresenter初始須要的對象,而後在@Provides定義一個MvpPresenter providePresenter(MvpActivity ui,MvpModel mvpModel)
方法,讓Dagger自動爲咱們建立一個MvpPresenter 對象
和傳統Dagger構建同樣,Component定義依賴的model,inject定義消耗的activity對象
@PerApp
@Singleton
@Component(modules = MvpPresenterModule.class)
public interface MvpPresenterComponent {
void inject(MvpActivity activity);
}複製代碼
public class MvpActivity extends AppCompatActivity implements MvpUiImpl{
@Inject
MvpPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp);
MvpPresenterComponent component= DaggerMvpPresenterComponent.builder().mvpPresenterModule(new MvpPresenterModule(this))
.build();
component.inject(this);
findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.testDoS();
}
});
}
@Override
public void showTest(String msg) {
TextView tv=(TextView)findViewById(R.id.tv);
tv.setText(msg);
}
}複製代碼
若有幫助歡迎start和留言!