關于MVP的基本知識網(wǎng)上已經(jīng)有很多了,但是很多都只是Demo,畢竟Demo跟實際運用之間還有無數(shù)個Debug,其實一開始我也看了很多關于MVP的介紹,其中有谷歌官方的Demo,還有很多技術博客,那個時候就覺得自己知道什么是MVP了,后來真正在自己項目中運用的時候,才發(fā)現(xiàn)并不是那么簡單,不過經(jīng)過一番折騰,逐漸對MVP有了比較深層次的認識,所以今天記錄分享一下。

我自己畫了一個關系圖,也就是最簡單的MVP結(jié)構(gòu)示意圖,我在這里并不會再解釋什么是MVP,今天我想把所有的認知轉(zhuǎn)化為代碼,也就是圖中的關系圖,他們之間的關系我全部都是用Callback來進行聯(lián)系的,也就是之前說的引用。
M層
- 這里的M層不是傳統(tǒng)意義上的Model,我更傾向于認為他是一個ModelManager,就是一個數(shù)據(jù)處理中心,可以處理網(wǎng)絡數(shù)據(jù),數(shù)據(jù)庫,文件以及關于Android中的四大組件的交互包含BroadcastReceiver,Service中的,都可以集中在這里面處理,有很長一段時間對于M的認知都是覺得就是個實體類,那個時候還以為自己掌握地很透徹,最后發(fā)現(xiàn)自己理解的其實是不對的,MddelManager持有Presenter的引用,M處理完數(shù)據(jù)之后通過Callback回調(diào)Presenter,Presenter由于持有View的引用,所以可以回調(diào)View
V層
- V就是指View(界面),往大了說是Activity或者Fragemnt,往小了說可以是一個Dialog、Toast或者Snakbar,具體就是直接跟用戶進行打交道的,View會實現(xiàn)Callback接口,然后傳遞給Presenter,然后Presenter會去ModelManager進行交互,然后數(shù)據(jù)處理完成之后,會通過Callback回調(diào)回來,這樣就完成了一個閉環(huán)
P層
- P就是Presenter,主持人其實挺形象的,就起一個客串的作用,相當于一座橋,來連接Vie跟ModelManger,很多文章是把邏輯在Presenter中進行處理的,我覺得不是很好,我認為在Modelmanager里面處理比較好,這樣解耦的更徹底,畢竟Presenter只是個中間的信使而已,不應該處理過多的邏輯。
關系搞清楚了,其實代碼實現(xiàn)就比較簡單
M層代碼
public class MainManager {
private ViewCallBack mViewCallBack;
public MainManager(ViewCallBack viewCallBack) {
this.mViewCallBack = viewCallBack;
}
public void getData() {
mViewCallBack.refreshView(1, "數(shù)據(jù)");
}
}
這里面只是寫了一個模板,可能一個界面需要多種數(shù)據(jù)處理方式,那么就根據(jù)需求在重新定義幾個方法即可
V層代碼
public interface ViewCallBack<V> {
/**
* @param code code:0:有數(shù)據(jù),1:數(shù)據(jù)為空,2:加載失敗
* @param data 定義好的數(shù)據(jù)類型
*/
void refreshView(int code, V data);
}
這里的V采取泛型的原因在于每個界面需要獲取的數(shù)據(jù)不一樣,所以用泛型加以區(qū)分,當一個界面需要獲取的接口很多,或者得到的數(shù)據(jù)結(jié)果類型不太一致的時候,這里的泛型就需要用Object來指定,然后在refreshView中通過數(shù)據(jù)的類型來判斷需要刷新的數(shù)據(jù)
P層代碼
public class MainPresenter {
private ViewCallBack mViewCallBack;
private MainManager mMainManager;
public MainPresenter(ViewCallBack viewCallBack) {
this.mViewCallBack = viewCallBack;
mMainManager = new MainManager(mViewCallBack);
}
public void getData() {
mMainManager.getData();
}
}
P層代碼的方法跟Manager對應,然后處理M層跟V層的Callback即可,但是注意Presenter是一個對象,需要在界面銷毀的時候置空,防止內(nèi)存泄露
我在demo中只是簡單寫了一個改變Text的值,當然在Manager里面可以進行任何你想要的操作,因為是采用接口回調(diào),運行一下看看效果

持續(xù)封裝
上面的只是一個Demo,下面進行封裝抽取,方便集成到真正的項目中去
- M層封裝
public abstract class BaseBeanManager {
protected ViewCallBack mViewCallBack;
protected HashMap<String, String> paramMap;
public BaseBeanManager(ViewCallBack modelCallBack) {
mViewCallBack = modelCallBack;
}
public abstract void getData();
}
- V層封裝
public abstract class BaseActivity<T extends BasePresenter, V> extends AppCompatActivity implements ViewCallBack<V> {
public T presenter;//泛型定義Presenter
@TargetApi(Build.VERSION_CODES.M)
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(getLayoutId());
presenter = initPresenter();
initViews();
initListener();
}
@Override
protected void onResume() {
super.onResume();
//初始化Presenter
if (presenter == null)
presenter = initPresenter();
//添加Callback
presenter.add((ViewCallBack) this);
}
protected abstract int getLayoutId();
protected abstract void initViews();
protected abstract void initListener();//初始化監(jiān)聽事件
protected abstract T initPresenter();//初始化Presenter
@Override
protected void onDestroy() {
super.onDestroy();
//生命周期結(jié)束時銷毀callback,并置空presenter
if (presenter != null){
presenter.remove();
presenter = null;
}
}
}
- P層封裝
public abstract class BasePresenter {
protected BaseBeanManager mBeanManager;//定義基類manager
protected HashMap<String, String> paramMap = new HashMap<>();
protected ViewCallBack mViewCallBack;
public BasePresenter(ViewCallBack viewCallBack) {
mViewCallBack = viewCallBack;
}
public void add(ViewCallBack viewCallBack) {
this.mViewCallBack = viewCallBack;
}
public void remove() {
this.mViewCallBack = null;
}
//默認的獲取數(shù)據(jù)的方法
protected abstract void getData();
}
使用
- M層
public class MainManager extends BaseBeanManager {
public MainManager(ViewCallBack modelCallBack) {
super(modelCallBack);
}
public void getData() {
mViewCallBack.refreshView(1, "MVP返回的數(shù)據(jù)");
}
}
2.V層
public class MainActivity extends BaseActivity<MainPresenter, String> implements ViewCallBack<String> {
private TextView tvDemo;
private Button btnGet;
@Override
protected int getLayoutId() {
return R.layout.activity_main;
}
@Override
protected void initViews() {
tvDemo = (TextView) findViewById(R.id.tv_demo);
btnGet = (Button) findViewById(R.id.btn_get);
}
public void initListener() {
btnGet.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
presenter.getData();
}
});
}
@Override
protected MainPresenter initPresenter() {
return new MainPresenter(this);
}
@Override
public void refreshView(int code, String data) {
tvDemo.setText(data);
}
}
- P層
public class MainPresenter extends BasePresenter {
public MainPresenter(ViewCallBack viewCallBack) {
super(viewCallBack);
}
public void getData() {
mBeanManager = new MainManager(mViewCallBack);
mBeanManager.getData();
}
}
本身是不想貼這么多代碼的,但是只有對比才能發(fā)現(xiàn),MVP由于解耦地比較徹底,所以滿足單一職責原則,新增了很多類,封裝之后,即使新建的類變多了,每個類都需要一個相應的Presenter,但是代碼量很少,所以看起來邏輯比較清楚
這就是我的項目中正在使用的的MVP,剛開始從MVC轉(zhuǎn)換過來的時候很不習慣,后來折騰了一陣子,發(fā)現(xiàn)其實挺好用的。