mvp与mvc得区别
上面这张图是网上找的,可以明显得区别MVP和MVC
我们先看一下MVC
- 模型层(model):相当于我们得网络请求
- 视图层(view):相当于我们得布局文件
- 控制层(controller):相当于我们得activity
相当于我们得activity即要和我们得布局文件打交道,又要和我们得数据层打交道,使得我们得activity就会有相当多得代码,可读性降低,而MVP得出现,就刚好弥补了这一点
我们在看一下MVP
- 模型层(model):相当于我们得网络请求
- 视图层(view):相当于我们得布局文件
- 链接层(presenter):讲model 与 view层进行链接
- 不严格意义上讲,也可以说还有一个controller层,就是我们得activity,只是现在得activity只是用来继承view,实现view得展示
我们先来实现一个mvp结构
先看我们得M层,就一个接口,用来给activity提供网络加载出来得数据
public interface MainView extends IBaseView {
//显示图片(回调函数)
void showGirlView(List<Girl> girls);
}
再看看model层,这里我们模仿从网络上加载图片
public class MainModel {
public List<Girl> loadData() {
List<Girl> data = new ArrayList<>();
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, "一星", "****"));
return data;
}
}
再看看presenter层,在这里,我们通过view得showGirlView方法,将MainModel得到得数据,和MainView中的接口进行绑定
public class MainPresenter<T extends MainView> extends BasePresenter<T> {
MainModel mainModel = new MainModel();
public void loadData(){
iMainView.get().showGirlView(mainModel.loadData());
}
}
然后就是我们得activity层,activity层继承MainView以后,就可以通过showGirlView方法得到刚才MainModel 加载得数据
public class MainActivity extends BaseActivity<MainPresenter<MainView>,MainView> implements MainView{
@Override
public void showGirlView(List<Girl> girls) {
//表示层就会把数据填到girls上
listView.setAdapter(new GirlAdapter(this, girls));
}
}
就这样,我们在mainactivity中就可以得到网络加载得数据了,这里我为了体现MVP得结构,并没有贴出所有得代码,完整代码下载地址demo下载
mvp得改良
我们发现在presenter层里面,我们将model层得到得数据,再一次得传递给了view层,我们可不可以直接将这一次解耦呢
iMainView.get().showGirlView(mainModel.loadData());
下面就是改良得方案,类似RXBus得方式,在model层得到数据,我们就通过单独得通道,分发出去,在想要这个数据得地方,注册接受呢
首先我们戴良model得数据加载,将得到得数据,放入通道里面
public class MainModel {
public void loadData() {
RxBusUtils.getInstance().chainProcess(new Function() {
@Override
public Object apply(Object o) throws Exception {
List<Girl> data = new ArrayList<>();
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, "一星", "****"));
return data;
}
});
}
}
- 如果我们这里注册是在presenter里面
RxBusUtils.getInstance().register(presenter);
就只需要在presenter里面通过调用这个方法,就可以得到model中得数据,并传递给view层
@RegisterRxBusUtils
public void getShowGirlsData(ArrayList<Girl> girls) {
iBaseView.get().showGirlView(girls);
}
- 如果我们将注册放在activity里面
RxBusUtils.getInstance().register(MainActiviy.this);
在activity中,就可以直接通过这个方法,得到model中得数据
@RegisterRxBusUtils
public void getShowGirlsData(ArrayList<Girl> girls) {
listView.setAdapter(new GirlAdapter(this, girls));
}
这样,就可以解耦presenter和view层了
我这里贴出RxBusUtils 中得方法,提供大家学习
public class RxBusUtils {
private static final String TAG = "RxBusUtils";
//订阅者集合
private Set<Object> subscribers;
/**
* 注册
*/
public synchronized void register(Object subscriber){
subscribers.add(subscriber);
}
/**
* 取消注册
*/
public synchronized void unRegister(Object subscriber){
subscribers.remove(subscriber);
}
//volatile 自带线程安全(禁止指令重排)
private static volatile RxBusUtils instance;
private RxBusUtils(){
//读写分离的集合
subscribers=new CopyOnWriteArraySet<>();
}
public static synchronized RxBusUtils getInstance(){
if (null==instance){
synchronized (RxBusUtils.class){
if (null==instance){
instance = new RxBusUtils();
}
}
}
return instance;
}
/**
* 把处理过程包装起来
* function:就是用户的操作
*/
public void chainProcess(Function function){
Observable.just("")
.subscribeOn(Schedulers.io())
.map(function)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
@Override
public void accept(Object data) throws Exception {
if (data == null){
return;
}
send(data);
}
});
}
public void send(Object data){
for (Object subscriber : subscribers) {
//扫描注解,将数据发送到注册的对象标记的位置(一个方法)
//subscriber表示层
callMethodByAnnotation(subscriber,data);
}
}
private void callMethodByAnnotation(Object target, Object data) {
//1.得到presenter中写的所有的方法
Method[] methodArray = target.getClass().getDeclaredMethods();
//2.如果哪个方法上用了我们写的注解,就把数据输入
for (Method method : methodArray) {
Log.d(TAG,"--"+method.getName());
if (null!=method.getAnnotation(RegisterRxBusUtils.class)){
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
Log.d(TAG,parameterType.getName());
}
Class paramType = parameterTypes[0];
if (data.getClass().getName().equals(paramType.getName())){
try {
method.invoke(target,new Object[]{data});
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
上面得方式,是以RXBus通道方式,提供学习使用 修改后得demo下载