Android开发之MVP模式
前言:在之前的开发中一直用的是mvc模式搭建的项目,所以我对于mvp也一直只是停留在理论和demo阶段上。正好现在的项目是被小伙伴借助dragger搭建的mvp模式的结构,所以就想着总结整理一下mvp模式的东西并写出来,也算是作为自己使用了mvp模式的标志。本文会先简单介绍一下几个常用的项目搭建模式,当然侧重点还是后面的mvp详解。
常用的几个模式:MVC、MVP、MVVM
MVC
对于MVC我想大家应该都不陌生,最典型的MVC就是JSP + servlet + javabean的模式了。
上面两张图是我从别的文章copy的,从中很容易看出MVC
的大致流程,用户通过操作View
来发送用户请求;Controller
接收到 用户请求 后,负责决定应该调用哪个Model
来进行处理;然后Model
根据用户请求进行相应的业务逻辑处理,并返回数据;最后Controller
调用相应的视图View
来显示Model
返回的数据。
MVVM
看上面的图(当然也是copy的),在MVVM
中有个ViewModel
,它的作用就是与View
进行双向绑定,当View
或者ViewModel
有一方变动时,另一方也会跟着改变,其实就是观察者模式,同时ViewModel
也会处理一些轻量的业务逻辑,具有和MVP
中的Presenter
的一些类似功能。当用户对View
进行操作时,ViewModel
就会直接收到指令,然后调用Model
处理业务逻辑,当Model
返回数据给ViewModel
时,因为ViewModel
与View
双向绑定的缘故,ViewModel
接收到数据后,View
也会跟着改变,省去了ViewModel
特意调用View
来改变View
的状态这一步骤!
MVP
首先,我们来看一下上图,View
发送指令给Presenter
,Presenter
获取指令后,调用响应的Model
进行业务逻辑处理,然后返回数据给Presenter
,Presenter
根据Model
返回的数据再来调用相应的View
。
为什么要用MVP?
在android开发中,相信大家应该都熟悉了mvc(model 、 view 、 control)。在Android的架构中Activity,fragment,布局的xml相当于View。然而在实际的开发过程中,Android的View层任务太繁重,大家将V和C都糅杂在Activity、Fragment中,这就导致了在实际开发中View层太过累赘,一不小,几次代码迭代过后,一个Activity或者Fragment中的代码就有几千行,有时候修改个功能在笨重的代码中摸爬滚打半天才找到关键点,对于不熟悉代码的开发者来说(或者前人编写代码质量太低)那代码迭代接手后简直是妙不可言。所以将视图和业务逻辑代码分开势在必行。
基于这个现状,Google设计了一个更优的框架模式来解决这个问题。就是目前实际开发中火热的MVP模式(model 、 view 、presenter)。用presenter将model和view隔离开来,一切业务逻辑处理都是通过presenter来进行操作,也就是说presenter是视图的数据的桥梁,视图和数据相隔两端,“可远观而不可亵玩”。强制只能使用presenter作为“邮递员”来”通信“。
MVP与MVC最大的不同之处是,MVP将M与V分隔开来,通过P交互,这样在Android中,就可以明确的把Activity当作View处理,虽然可能还有一点逻辑在其中,但是已经无伤大雅;View和Model不直接交互,当View有变动或者Model有变动时,不会相互影响,有太大变动,,耦合性低,对于后期维护来说,特别是项目越来越庞大时,可以很快的理清项目结构,找到需要修改的地方,大大的缩短了工作量。而且,因为View与Model分离的缘故,Model可以单独进行单元测试。
MVP代码结构
首先是View和presenter的接口,抽象出view对象的绑定方法。
IView.java
public interface IView {
void bindView();
void UnbindView();
}
IPresenter.java
public interface IPresenter {
void register(V view);
void unRegister();
}
BasePresenter实现IPresenter接口,为业务逻辑层presenter的基类。用弱引用来接收View的对象,在取消注册的时候销毁view对象,保证View不会造成内存泄漏。
BasePresenter.java
public class BasePresenter implements IPresenter {
protected WeakReference iView;
@Override
public void register(V view) {
Log.i(TAG, "BasePresenter register: ");
iView = new WeakReference(view);
}
@Override
public void unRegister() {
Log.i(TAG, "BasePresenter unRegister: ");
iView.clear();
iView = null;
}
BaseActivity实现IView接口,为视图层的基类(也就是Activity的基类),这是一个抽象类,实现了视图层到业务逻辑层的绑定与解绑,抽象方法createPresenter()子类必须实现,来确保不通的业务逻辑层。
BaseActivity.java
public abstract class BaseActivity
extends Activity implements IView{
protected P iPresenter;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
bindView();
}
@Override
protected void onDestroy() {
super.onDestroy();
UnbindView();
}
@Override
public void bindView() {
iPresenter = createPresenter();
iPresenter.register(this);
}
@Override
public void UnbindView() {
iPresenter.unRegister();
}
protected abstract P createPresenter();
}
接下来是具体的使用MVP的流程了,定义三方交接接口。
public interface DemoContract {
interface View{
void demoView(String test);
}
interface Presenter{
void demoPresenter();
}
interface Model{
void demoModel(ModelListener modelListener);
interface ModelListener{
void completed(String test);
}
}
视图层DemoActivity.java继承BaseAcitivity实现createPresenter()方法,DemoContract.View接口。
public class DemoActivity extends BaseActivity implements DemoContract.View {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
iPresenter.demoPresenter();
}
@Override
protected DemoPresenter createPresenter() {
return new DemoPresenter();
}
@Override
public void demoView(String test) {
Toast.makeText(this, test, Toast.LENGTH_LONG).show();
}
业务逻辑层DemoPresenter.java继承BasePresenter实现DemoContract.Presenter接口。
public class DemoPresenter extends BasePresenter implements DemoContract.Presenter {
DemoContract.Model model = new DemoModel();
@Override
public void demoPresenter() {
model.demoModel(new DemoContract.Model.ModelListener() {
@Override
public void completed(String test) {
iView.get().demoView(test);
}
});
}
数据实体层DemoModel.java实现DemoContract.Model接口,用接口回调异步返回数据。
public class DemoModel implements DemoContract.Model{
@Override
public void demoModel(ModelListener modelListener) {
modelListener.completed("mvp test");
}
到此为止,上面的代码流程就是我使用mvp的方式,当然了使用流程不是固定的,每个人都可以根据自己的风格和喜好进行变形什么的。
MVP优缺点
优点:最大的优点剥离了视图层和业务逻辑层,让各个类的分工更为明确,逻辑更为清晰,代码扩展性更高,后期代码迭代更新更加容易,同时也方便了单元测试的编写,以前将视图与业务混合在一起的时候,要写单元测试很多时候真的是无从下手。相对于MVP模式来说写单元测试就更加容易了。因为职责更加清晰,测试的目标就明确多了。
缺点:相对而言,MVP模式的代码量就多了,类文件也多了,简单的一个业务逻辑操作就要各方来配合协作(即是需要presenter 和 view的接口)。但是这个问题完全在可以接收的范围。完全符合Java的抽象封装设计原则(接口隔离,开闭原则,里氏代换)。
可能存在的问题:Model进行一步操作的时候,获取结果通过Presenter会传到View的时候,出现View引用的空指针异常。Presenter和View相互持有引用,解除不及时的话容易出现内存泄漏。
好了,文章到此结束了,希望对你有所帮助,see you
上一篇: 一款上手即用的Java代码混淆工具
下一篇: 一个关于JS正则匹配的踩坑记录