最近在學(xué)習(xí)關(guān)于MVP框架的東西,網(wǎng)上找了好多資料,但是都覺得好晦澀難懂(可能是因?yàn)樽约禾死怖怖怖怖怖玻?。所以打算自己寫一個(gè)最最最簡單的demo。事先申明:僅希望能給初識(shí)MVP的同學(xué)一些想法和思路。好了廢話不多說。
首先要讀懂MVP框架,首先就需要清楚java 的接口回調(diào)機(jī)制(什么?!不太懂?老子反手就是…………一本《Java從入門到放棄》)。不是非常清楚的同學(xué)抓緊去補(bǔ)課。MVP框架個(gè)人理解沒有一種固定的寫法,只要是符合其思想的都可以算做MVP框架(這也是網(wǎng)上好多例子賊難懂的原因之一),所以最關(guān)鍵還是要去理解其最重要的思想。
MVP
先上一張圖,后面結(jié)合代碼再慢慢解釋。

首先先對(duì)三個(gè)元素做個(gè)介紹:
View:視圖層(Activity,fragment)
Presenter:連接view和module的樞紐,一切邏輯控制都由它負(fù)責(zé)
Module:數(shù)據(jù)模型,數(shù)據(jù)處理
圖中向下的黑色箭頭表示直接調(diào)用,而向上的黃色箭頭則表示接口回調(diào)!
舉個(gè)例子?
這個(gè)例子是模擬異步處理處理數(shù)據(jù)之后,用一個(gè)listview數(shù)據(jù)展示。簡單粗暴的一個(gè)例子。
Mudule(數(shù)據(jù))
Module——也就是M。這里面有一個(gè)接口類和一個(gè)module類。接口的作用是當(dāng)M將數(shù)據(jù)處理完畢之后通過接口去通知P繼續(xù)執(zhí)行下面的顯示操作。
ModuleInterface:
public interface ModuleInterface {
//獲取數(shù)據(jù)狀態(tài)回調(diào)的接口
void LoadSuccess(List<String> data);
void LoadFailed();
}
DataModule:
public class DataModule {
List data = new ArrayList();
ModuleInterface mCallback;
public DataModule(ModuleInterface moduleInterface){
this.mCallback = moduleInterface;
}
//模擬數(shù)據(jù)處理,當(dāng)然可以換成網(wǎng)絡(luò)請(qǐng)求等。
public void getdata() {
Observable.create(new ObservableOnSubscribe<List<String>>() {
@Override
public void subscribe(@NonNull ObservableEmitter<List<String>> e) throws Exception {
for (int i = 0; i <100; i++) {
data.add(i + "items");
}
e.onNext(data);
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<List<String>>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(List<String> strings) {
//數(shù)據(jù)準(zhǔn)備成功后,通過接口通知P:數(shù)據(jù)已經(jīng)準(zhǔn)備完畢,可以繼續(xù)下面的邏輯操作
mCallback.LoadSuccess(strings);
}
@Override
public void onError(Throwable e) {
//數(shù)據(jù)準(zhǔn)備失敗
mCallback.LoadFailed();
}
@Override
public void onComplete() {
}
});
}
Presenter
Presenter——也就是P。它的主要作用就是負(fù)責(zé)邏輯控制,它負(fù)責(zé)去告訴M去準(zhǔn)備數(shù)據(jù),等數(shù)據(jù)完成之后再交給V去負(fù)責(zé)展示。這里也是一個(gè)MvpPresenter類和一個(gè)MvpviewInterface接口。
MvpViewInterface:
public interface MvpViewInterface {
void showLoading();
void hideLoading();
void setListItem(List<String> data);
void failed();
void showMessage(String message);
}
MvpPresenter:
public class MvpPresenter implements ModuleInterface{
private MvpView mvpView;
//獲取Module實(shí)例,執(zhí)行數(shù)據(jù)處理方法。
DataModule dataModule = new DataModule(this);;
public MvpPresenter(MvpView mvpView){
this.mvpView = mvpView;
}
//開始執(zhí)行邏輯
public void handledata() {
mvpView.showLoading();
dataModule.getdata();
}
public void onItemClick(int position){
mvpView.showMessage("點(diǎn)擊了item"+position);
}
//數(shù)據(jù)傳過來之后,繼續(xù)執(zhí)行邏輯
@Override
public void LoadSuccess(List<String> data) {
mvpView.hideLoading();
mvpView.setListItem(data);
}
@Override
public void LoadFailed() {
//處理失敗后View的操作
mvpView.failed();
}
}
View
View——也就是視圖層,就只需要將p轉(zhuǎn)給它的數(shù)據(jù)展示出來就可以了。實(shí)現(xiàn)一下MvpViewInterface里面的方法就可以了。
public class MvpActivity extends AppCompatActivity implements MvpViewInterface,AdapterView.OnItemClickListener{
private ListView mvpListView;
private MvpPresenter mvpPresenter;
private ProgressBar pb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp);
mvpListView = (ListView)findViewById(R.id.mvp_listview);
mvpListView.setOnItemClickListener(this);
pb = (ProgressBar) findViewById(R.id.mvp_loading);
//獲取MvpPresenter實(shí)例
mvpPresenter = new MvpPresenter(this);
//開始執(zhí)行,直接調(diào)用P中方法
mvpPresenter.handledata();
}
@Override
public void showLoading() {
pb.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading() {
pb.setVisibility(View.GONE);
}
@Override
public void setListItem(List<String> data) {
ArrayAdapter adapter = new ArrayAdapter(MvpActivity.this,android.R.layout.simple_list_item_1,data);
mvpListView.setAdapter(adapter);
}
@Override
public void failed() {
Toast.makeText(MvpActivity.this,"加載失敗",Toast.LENGTH_SHORT).show();
}
@Override
public void showMessage(String message) {
Toast.makeText(this,message,Toast.LENGTH_SHORT).show();
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mvpPresenter.onItemClick(position);
}
}
到此例子就結(jié)束了,接下來我們?cè)俳Y(jié)合那張圖來看。首先V中直接調(diào)用了P中的handledata()方法開始整個(gè)流程,并且在handledata()中直接調(diào)用了M中的getdata()方法(通知M該準(zhǔn)備數(shù)據(jù)了)。這就是指代那兩條黑色箭頭(直接調(diào)用)。接下來當(dāng)數(shù)據(jù)處理結(jié)束后又會(huì)通過回調(diào)去執(zhí)行P中的接口方法,繼而回調(diào)執(zhí)行V中的接口方法。這就是指代那兩個(gè)兩個(gè)黃色箭頭(接口回調(diào))。
關(guān)于MVP框架的一些作用,好處啥的就不在此多做說明了。很多博客里面都有介紹。
這里是demo地址
結(jié)束語:
本文只意在希望能給初識(shí)MVP的同學(xué)一些想法和思路。例子是十分比較簡單粗糙的。真正在實(shí)際使用中還需要考慮耦合等一些其他問題。最后本人也是菜鳥一枚。第一次寫簡書。
如果有錯(cuò)誤之處,歡迎指正!
補(bǔ)上仿GoogleMVPDemo的Demo
一個(gè)最最最簡單的MVP框架Demo(下)