在刚开始做项目的时候采用的都是MVC的模式开发的,但是接触MVP模式后,感觉真的不一样,MVP模式虽然导致类的增加,但是activity中代码减少了很多,同时整洁性提高了很多,所以在之后的项目开发中肯定会采用MVP模式开发。
MVC模式:
M—>Model:业务逻辑和实体模型
V—->View:对应的布局文件
C—->Controllor对应于Activity
通过MVC模型图可以看出,Controller中持有Model的引用,也持有View的引用,但是Model和View之间又相互持有引用,事件处理代码都在activity中,造成了activity既像View又像Controller,这样就导致了MVC变成了双层模型。
再来看下MVP模式
MVP模式:
M—>Model:业务逻辑和实体模型
V—>View:对应activity,负责View的绘制以及用户交互
P—>Presenter:负责完成View和Model之间的交互
通过MVP模型图可以看出,Presenter中只有Model的引用,也持有View的引用,但是Model和View之间并没有关系,都是通过Presenter进行交互,这样就将Model和View之间隔离了,降低了它们之间耦合度,体现出MVP模式是一种三次模型。
MVP模式相对于MVC模式优点:
- 减少了Activity的职责,简化了activity中的代码,将复杂的逻辑代码提取到了Presenter中进行处理,与之对应的好处就是耦合度降低了,activity代码变得更加简洁。
- 方便进行单元测试
- 避免activity内存泄漏
MVP模式及BaseActivity的简单封装
使用MVP模式首先要建立相应的Model、View、Presenter类,
首先建立View接口,提供loading()、loadSuccess(List grils)、loadFail(int errorCode)等方法,有对应的activity去实现该接口,进行数据回调,更新ui;
/**
* Created by Administrator on 2017/12/20.
* View层接口
*/
public interface IGrilView {
/**
* 加载
*/
void loading();
/**
* 成功
* @param grils
*/
void loadSuccess(List<Girl> grils);
/**
* 加载失败
* @param errorCode
*/
void loadFail(int errorCode);
}
建立Model层接口,提供了loadGirl()等方法和内部接口,具体的业务逻辑由其实现了去实现;
/**
* Created by Administrator on 2017/12/20.
* 模型接口
*/
public interface IGirlModel {
void loadGirl(GirlOnLoadListener listener);
interface GirlOnLoadListener{
/**
* 加载中
*/
void onLoading();
/**
* 加载成功
* @param girlList
*/
void onSuccess(List<Girl> girlList);
/**
* 加载失败
* @param errorCode
*/
void onFail(int errorCode);
}
}
Model层具体实现类:
/**
* Created by Administrator on 2017/12/20.
* 具体模型实现类
*/
public class GirlModelImlV1 implements IGirlModel {
Handler handler=new Handler(Looper.getMainLooper());
@Override
public void loadGirl(final GirlOnLoadListener listener) {
//加载中回调
listener.onLoading();
new Thread()
{
@Override
public void run() {
try {
sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
final List<Girl> data = new ArrayList<Girl>();
data.add(new Girl(R.drawable.f1, "五颗星", "佰仟媚儿初夏新款韩版时尚潮流女个性字母印花无袖露脐上衣"));
data.add(new Girl(R.drawable.f2, "四颗星", "迷依诗诺夏天新款韩版女装性感夜店欧美风字母印花牛仔露脐背心上衣"));
data.add(new Girl(R.drawable.f3, "五颗星", "迷依诗诺春夏欧美新款性感女装单排扣牛仔背心露脐上衣"));
data.add(new Girl(R.drawable.f4, "三颗星", "美莉丹 新款欧美单排扣牛仔背心露脐上衣"));
data.add(new Girl(R.drawable.f5, "五颗星", "夏季新款韩版时尚个性字母无袖露脐上衣"));
data.add(new Girl(R.drawable.f6, "三颗星", "新款欧美单排扣牛仔背心露脐上衣"));
data.add(new Girl(R.drawable.f7, "四颗星", "夏装新款下摆波浪边挂脖露肩"));
data.add(new Girl(R.drawable.f8, "五颗星", "夏天新款欧美时尚潮流休闲百"));
data.add(new Girl(R.drawable.f9, "四颗星", "迷依诗诺夏季新款小香风甜美性感夜"));
data.add(new Girl(R.drawable.f10, "三颗星", "安巴克夏季新款韩版时尚套装性感"));
handler.post(new Runnable() {
@Override
public void run() {
//回调 加载成功回调
listener.onSuccess(data);
}
});
}
}.start();
}
}
建立抽象的Persenter层,里面提供对应的软引用及绑定和解除view的方法,这样可以避免activity的内存溢出,具体的Model和View之间的交互由其子类去完成;
/**
* Created by Administrator on 2017/12/20.
* T 对应着Activity 的UI抽象接口 视图
*/
public abstract class BasePersenter<T> {
/**
* 持有ui接口的弱引用
*/
protected WeakReference<T> mViewRef;
/**
* 获取数据的方法
*/
public abstract void fectch();
/**
* 将activity和view绑定
*
* @param view
*/
public void attachView(T view) {
mViewRef = new WeakReference<T>(view);
}
/**
* 将view和activity解绑
*/
public void detach() {
if (mViewRef != null) {
mViewRef.clear();
mViewRef = null;
}
}
}
Persenter子类:
/**
* Created by Administrator on 2017/12/20.
* 具体Persenter子类
*/
public class GirlPresentV1<T> extends BasePersenter<IGrilView> {
/**
* 持有视图层 ui接口的引用,此时的视图层是activity
*/
IGrilView mGrilView;
public GirlPresentV1(IGrilView mGrilView) {
this.mGrilView = mGrilView;
}
/**
* 持有model的引用
*/
IGirlModel girlModel = new GirlModelImlV1();
@Override
public void fectch() {
if (girlModel != null) {
//参数回调
girlModel.loadGirl(new IGirlModel.GirlOnLoadListener() {
@Override
public void onLoading() {
mGrilView.loading();
}
@Override
public void onSuccess(List<Girl> girlList) {
//回调视图
mGrilView.loadSuccess(girlList);
}
@Override
public void onFail(int errorCode) {
mGrilView.loadFail(errorCode);
}
});
}
}
}
同时将activity中的代码抽取出来建立一个BaseActivity;
/**
* Created by Administrator on 2017/12/20.
*/
public abstract class BaseActivty<V, T extends BasePersenter<V>> extends Activity {
protected T mPersent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
mPersent = createPresent();
mPersent.attachView((V) this);
initView();
}
/**
* 初始化控件
*/
protected void initView() {
}
@Override
protected void onDestroy() {
mPersent.detach();
super.onDestroy();
}
/**
* 获取布局文件layout
*
* @return
*/
protected abstract int getLayoutId();
/**
* 子类实现具体的构建过程
*
* @return
*/
protected abstract T createPresent();
/**
* 字符串为空判断
*
* @param value
* @return
*/
protected String stringToString(String value) {
return value == null ? "" : value;
}
/**
* 通过viewid返回一个view对象
*
* @param viewId
* @param <T>
* @return
*/
protected <T extends View> T findView(int viewId) {
return (T) super.findViewById(viewId);
}
/**
* 判断List集合是否为空
*
* @param list
* @return
*/
protected List<T> newList(List<T> list) {
if (list == null) {
list = new ArrayList<>();
}
return list;
}
/**
* activity之间的跳转
*
* @param clazz
* @param map
*/
protected void startActivity(Class clazz, Map<String, Object> map) {
Intent intent = new Intent(this, clazz);
if (map != null && map.size() != 0) {
bindData(intent, map);
}
startActivity(intent);
}
protected void startActivityForResult(Class clazz, Map<String, Object> map, int requestCode) {
Intent intent = new Intent(this, clazz);
if (map != null && map.size() != 0) {
bindData(intent, map);
}
startActivityForResult(intent, requestCode);
}
/**
* activity之间传值跳转
*
* @param intent
* @param map
*/
private void bindData(Intent intent, Map<String, Object> map) {
Bundle bundle = new Bundle();
//遍历map集合
Set<Map.Entry<String, Object>> entries = map.entrySet();
for (Map.Entry<String, Object> entry : entries) {
Object value = entry.getValue();
String key = entry.getKey();
if (value instanceof String) {
bundle.putString(key, (String) value);
} else if (value instanceof Integer) {
bundle.putInt(key, (int) value);
} else if (value instanceof Boolean) {
bundle.getBoolean(key, (boolean) value);
} else if (value instanceof Long) {
bundle.putLong(key, (long) value);
} else if (value instanceof Double) {
bundle.putDouble(key, (double) value);
} else if (value instanceof Float) {
bundle.putFloat(key, (float) value);
} else {
continue;
}
}
intent.putExtras(bundle);
}
}
后面的activity只需要extends BaseActivity 实现页面ui加载及用户交互即可;
public class MainActivity extends BaseActivty<IGrilView,GirlPresentV1<IGrilView>> implements IGrilView {
private RecyclerView recyclerVew;
@Override
protected int getLayoutId() {
return R.layout.activity_main;
}
@Override
protected void initView() {
super.initView();
recyclerVew = (RecyclerView) findViewById(R.id.recycler_view);
//设置布局管理器
recyclerVew.setLayoutManager(new LinearLayoutManager(this));
mPersent.fectch();
}
@Override
protected GirlPresentV1<IGrilView> createPresent() {
return new GirlPresentV1<>(this);
}
@Override
public void loading() {
//加载中回调
Toast.makeText(this,"正在拼命加载", Toast.LENGTH_SHORT).show();
}
@Override
public void loadSuccess(List<Girl> grils) {
//加载成功回调
recyclerVew.setAdapter(new GirlAdapter(this,grils));
}
@Override
public void loadFail(int errorCode) {
//加载失败回调
}
}
这样一个简单的MVP模式及BaseActivity封装就完成了,效果如下: