赞
踩
导读:MVP模式是MVC模式在Android上的一种变体,要介绍MVP就得先介绍MVC。在MVC模式中,Activity应该是属于View这一层。而实质上,它既承担了View,同时也包含一些Controller的东西在里面。这对于开发与维护来说不太友好,耦合度大高了。把Activity的View和Controller抽离出来就变成了View和Presenter,这就是MVP模式。
MVC模式
MVC模式的结构分为三部分,实体层的Model,视图层的View,以及控制层的Controller。
• 其中View层其实就是程序的UI界面,用于向用户展示数据以及接收用户的输入
• 而Model层就是JavaBean实体类,用于保存实例数据
• Controller控制器用于更新UI界面和数据实例
例如,View层接受用户的输入,然后通过Controller修改对应的Model实例;同时,当Model实例的数据发生变化的时候,需要修改UI界面,可以通过Controller更新界面。(View层也可以直接更新Model实例的数据,而不用每次都通过Controller,这样对于一些简单的数据更新工作会变得方便许多。)
MVP模式
按照MVC的分层,Activity和Fragment(后面只说Activity)应该属于View层,用于展示UI界面,以及接收用户的输入,此外还要承担一些生命周期的工作。Activity是在Android开发中充当非常重要的角色,特别是它的生命周期的功能,所以开发的时候我们经常把一些业务逻辑直接写在Activity里面,这非常直观方便,代价就是Activity会越来越臃肿。因此,Activity不仅承担了View的角色,还承担了一部分的Controller角色,这样一来V和C就耦合在一起了,虽然这样写方便,但是如果业务调整的话,要维护起来就难了,而且在一个臃肿的Activity类查找业务逻辑的代码也会非常麻烦,所以看起来有必要在Activity中,把View和Controller抽离开来,而这就是MVP模式的工作了。
MVP模式的核心思想:
MVP把Activity中的UI逻辑抽象成View接口,把业务逻辑抽象成Presenter接口,Model类还是原来的Model。
这就是MVP模式,现在这样的话,Activity的工作的简单了,只用来响应生命周期,其他工作都丢到Presenter中去完成。从上图可以看出,Presenter是Model和View之间的桥梁,为了让结构变得更加简单,View并不能直接对Model进行操作,这也是MVP与MVC最大的不同之处。
MVP模式的作用
• 分离了视图逻辑和业务逻辑,降低了耦合 • Activity只处理生命周期的任务,代码变得更加简洁
• 视图逻辑和业务逻辑分别抽象到了View和Presenter的接口中去,提高代码的可阅读性
• Presenter被抽象成接口,可以有多种具体的实现,所以方便进行单元测试。需要的时候可以随意切换presenter改变实
现方式。当presenter代码过于庞大时,还可以整理出多个presenter 互相调用。
• 把业务逻辑抽到Presenter中去,避免后台线程引用着Activity导致Activity的资源无法被系统回收从而引起内存泄露和OOM
MVP模式代码实例结构分析
从上面图可以看到,MVP package下包含domian,model,presenter,ui 三个package.
Domian下放各个模块的Contract 功能实现的函数声明。方便调用查看。
Model 下放各个模块的Model 层。Model层的主要功能为 获取数据。
Presenter 下放各个模块的 Presenter层。Presenter 层的主要功能 为 用户的一些逻辑操作。
Ui 下放各个模块的Ui层。Ui层的主要功能为用户的主activity。主线程用户界面显示。
这里以Music 功能模块为例分析以上三个结构模块之间的调用关系。
MusicActivity
public class MusicActivity extends BaseActivity implements SpeechInputContract.IMusicView {
@BindView(R.id.recyclerview)
RecyclerView recyclerview;
View headView1;
TextView tvSongName;
TextView tvSingerAndAlbum;
ImageView imgCover;
ImageView btnPlay;
/* TextView btnLyricsControl;
TextView tvLyrics;*/
private PlayListAdapter playListAdapter;
MusicPlayService musicPlayService;
private void initMusic(final MusicPlayBean musicPlayBean){…..}
@Override
protected int setRootViewId() {
return R.layout.activity_music;
}
@Override
protected void initData(){
…数据的初始化..
playListAdapter = new PlayListAdapter();
initView();
…
}
private void initView(){
…
tvSongName = (TextView) headView1.findViewById(R.id.tv_song_name);
btnPlay.setOnClickListener
…
}
@Override
public void getMusicDataSuccess(List<MusicPlayBean> musicPlayBeanList) {
// playListAdapter.addData(musicPlayBeanList);
}
@Override
public void controlMusic(String playState, int index) {
if (null != musicPlayService) {
musicPlayService.changePlayState(playState);
}
}
@Override
protected void onResume() {…}
@Override
protected void onPause(){…}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
SpeechInputContract
在musicAcitivity 类继承SpeechInputContract.IMusicView
interface IMusicView extends IBaseView {
/**
* 获取音乐源成功
*
* @param musicPlayBeanList 获取到的音乐源
*/
void getMusicDataSuccess(List<MusicPlayBean> musicPlayBeanList);
/**
* 音乐控制
*
* @param playState 不用枚举是因为 1、离线识别返回就是STRING 方便 2、枚举消耗内存
*/
void controlMusic(String playState, int index);
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
这些接口在Activity 中实现。在presenter 中调用,以实现在presenter中控制ui。
MusicPresenter
public class MusicPresenter {
IMusicView musicView;
MusicModel musicModel;
public MusicPresenter(IMusicView musicView) {
this.musicView = musicView;
musicModel = new MusicModel();
}
这里传入MusicView 就可以通过接口调用直接控制界面显示,直接控制MusicView.
实例化 MusicModel ,获取Music模块相关的数据
public void getMusicData(String requirement) {
if (null != musicView) {
musicModel.getMusicData(requirement, new <KugouMusicBean>(musicView) {
@Override
public void onSuccess(KugouMusicBean kugouMusicBean, Call call, Response response) {
…
musicView.getMusicDataSuccess(dateList);
…
}
}
public void setMusicState(String musicState) {
if (null != musicView) {
musicView.controlMusic(musicState, -1);
}
}
public void release() {
if (null != musicModel) {
musicModel.release();
}
musicModel = null;
musicView = null;
}
}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
从以上可以看出 在MusicPresenter 中直接调用musicModel 和MusicView 中的相关接口,
MusicActivity 中只做了控件的初始化等简单的操作。使Activity的代码结构简单。
MusicModel
public class MusicModel extends BaseModel implements SpeechInputContract.IMusicModel {
@Override
public void getMusicData(String requirement, AbsCallback callback){…}
@Override
public void release(){…}
}
再看看MusicPresenter 初始化和引用的地方
SpeechInputPresenter
public class SpeechInputPresenter extends SpeechInputContract.ISpeechInputPresenter {
MusicPresenter musicPresenter;
musicPresenter = new MusicPresenter((SpeechInputContract.IMusicView) getContext());
}
当录音并识别完成时,NLI 返回值 recognizeBean 。对这个结果进行分析处理并进行相应的逻辑和ui显示。
private String dealRecognizeBean(RecognizeBean recognizeBean)
{…
if (recognizeBean.getApiType().equals(MUSIC.getName())) {
{
switch (semantic.getGlobalModifiers()[0]) {
case MUSIC_PLAY:
if (semantic.hasSlots()) {
musicPresenter.getMusicData(semantic.getSlots()[0].getValue());
} else {
musicPresenter.getMusicData(getContext().getString(R.string.recommend_music));
}
tempShowResult = getContext().getString(R.string.go_to_play);
break;
case MUSIC_PAUSE:
musicPresenter.setMusicState(PAUSE);
tempShowResult = getContext().getString(R.string.go_to_pause);
break;
case MUSIC_PRE:
musicPresenter.setMusicState(PRE_SONG);
tempShowResult = getContext().getString(R.string.go_to_play);
break;
case MUSIC_NEXT:
musicPresenter.setMusicState(NEXT_SONG);
tempShowResult = getContext().getString(R.string.go_to_play);
break;
}
…}
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。