分分鐘理解什麼叫MVP模式

分分鐘理解什麼叫MVP模式

MVP 是從經典的模式MVC演變而來,它們的基本思想有相通的地方:Controller/Presenter負責邏輯的處理,Model提供數據,View負責顯示。作爲一種新的模式,MVP與MVC有着一個重大的區別:在MVP中View並不直接使用Model,它們之間的通信是通過Presenter (MVC中的Controller)來進行的,所有的交互都發生在Presenter內部,而在MVC中View會從直接Model中讀取數據而不是通過 Controller。
在MVC裏,View是可以直接訪問Model的!從而,View裏會包含Model信息,不可避免的還要包括一些業務邏輯。 在MVC模型裏,更關注的Model的不變,而同時有多個對Model的不同顯示,及View。所以,在MVC模型裏,Model不依賴於View,但是View是依賴於Model的。不僅如此,因爲有一些業務邏輯在View裏實現了,導致要更改View也是比較困難的,至少那些業務邏輯是無法重用的。
這裏寫圖片描述

我們直接看代碼:

我們把可視化組件統一當成View,這裏面把Activity,Fragment也歸類爲View層:
MainActivity:

package com.kakasure.mvpdemo.v;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import com.kakasure.mvpdemo.R;
import com.kakasure.mvpdemo.callback.ActivityCallback;
import com.kakasure.mvpdemo.p.MainPersenter;

/**
 * @author dashentao
 * @date 2015 9-21
 */
public class MainActivity extends AppCompatActivity implements ActivityCallback {
    private Button button;
    private TextView textview;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.button1);
        textview = (TextView) findViewById(R.id.textview1);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MainPersenter.getInstance().Opreation1(MainActivity.this);
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void toUI(int action, Object object) {
        switch (action) {
            case MainPersenter.ACTION_1:
                if (object != null) {
                    textview.setText((String) object);
                }
                break;
            default:
                break;
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        MainPersenter.getInstance().destoryInstance();
    }
}

P層負責請求的封裝與結果的回調:

package com.kakasure.mvpdemo.p;

import android.graphics.AvoidXfermode;
import android.os.Message;

import com.kakasure.mvpdemo.callback.ActivityCallback;
import com.kakasure.mvpdemo.m.Model;

import java.util.AbstractCollection;

/**
 * Created by Administrator on 2015/9/21.
 */
public class MainPersenter extends BasePersenter {
    private static MainPersenter persenter;
    private static Object object = new Object();

    public static MainPersenter getInstance() {
        if (persenter == null) {
            synchronized (object) {
                if (persenter == null) {
                    persenter = new MainPersenter();
                }
            }
        }
        return persenter;
    }

    /**
     * 操作
     */
    public void Opreation1(ActivityCallback activityCallback) {
        mActivityCallback = activityCallback;
        Model model = new Model();
        String result = model.test1();
        Message message = Message.obtain();
        message.what = ACTION_1;
        message.obj = result;
        sendMsg(message);
    }

    @Override
    public void destoryInstance() {
        if (persenter != null) {
            persenter = null;
            object = null;
        }
    }
}

核心的回調功能具體由BaseP統一負責:

package com.kakasure.mvpdemo.p;


import android.os.Handler;
import android.os.Looper;
import android.os.Message;

import com.kakasure.mvpdemo.callback.ActivityCallback;

/**
 * Created by Administrator on 2015/9/21.
 */
public abstract class BasePersenter {
    protected ActivityCallback mActivityCallback;
    /**
     * 動作唯一綁定標誌
     */
    public static final int ACTION_1 = 1;

    private void toUI(Message msg) {
        if (mActivityCallback != null) {
            mActivityCallback.toUI(msg.what, msg.obj);
        }
    }

    private Handler myHandler = new Handler(Looper.myLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            toUI(msg);
        }
    };

    protected void sendMsg(Message message) {
        myHandler.sendMessage(message);
    }

    /**
     * 調用實例銷燬時同步銷燬Persenter實例,避免單例長期被持有,導致潛在的內存泄露
     */
    public abstract void destoryInstance();
}

Model層:
主要負責數據的組合

package com.kakasure.mvpdemo.m;

/**
 * Created by Administrator on 2015/9/21.
 */
public class Model {
    public Model() {}

    public String test1() {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 10; i++) {
            sb.append(i + "");
        }
        return sb.toString();
    }
}

回調接口(非常重要):

package com.kakasure.mvpdemo.callback;

import android.animation.ObjectAnimator;

/**
 * Created by Administrator on 2015/9/21.
 */
public interface ActivityCallback {
    /**
     * return to UI<br/>
     *
     * @param action
     * @param object
     */
    void toUI(int action, Object object);
}

BaseP會通過由操作實例註冊進來的callback進行數據分發:

button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MainPersenter.getInstance().Opreation1(MainActivity.this);
            }
        });
 /**
     * 操作
     */
    public void Opreation1(ActivityCallback activityCallback) {
        mActivityCallback = activityCallback;
        Model model = new Model();
        String result = model.test1();
        Message message = Message.obtain();
        message.what = ACTION_1;
        message.obj = result;
        sendMsg(message);
    }
private void toUI(Message msg) {
        if (mActivityCallback != null) {
            mActivityCallback.toUI(msg.what, msg.obj);
        }
    }

    private Handler myHandler = new Handler(Looper.myLooper()) {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            toUI(msg);
        }
    };

    protected void sendMsg(Message message) {
        myHandler.sendMessage(message);
    }

最後數據的返回結果丟給調用實例進行處理:
這樣View層根本不需要關心數據的組裝過程,只關心結果,從而達到功能解耦。

 @Override
    public void toUI(int action, Object object) {
        switch (action) {
            case MainPersenter.ACTION_1:
                if (object != null) {
                    textview.setText((String) object);
                }
                break;
            default:
                break;
        }
    }

有幾點需要特別注意:
1:請求動作的Action標誌做唯一化,這樣容易管理,並且功能區分明顯;

public abstract class BasePersenter {
    protected ActivityCallback mActivityCallback;
    /**
     * 動作唯一綁定標誌
     */
    public static final int ACTION_1 = 1;

2 : 當Activity銷燬不用時儘量調用destoryInstance釋放單例實例,避免長期持有,造成潛在的內存泄露:

    @Override
    protected void onDestroy() {
        super.onDestroy();
        MainPersenter.getInstance().destoryInstance();
    }
}

這裏只是拋磚引玉,具體的封裝自己可以隨便玩,哈哈

github代碼鏈接:https://github.com/dashentao1989/MvpDemo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章