分分鐘理解什麼叫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