分分钟理解什么叫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