Android MVP Pattern 学习总结

导读:MVP模式是MVC模式在Android上的一种变体,要介绍MVP就得先介绍MVC。在MVC模式中,Activity应该是属于View这一层。而实质上,它既承担了View,同时也包含一些Controller的东西在里面。这对于开发与维护来说不太友好,耦合度大高了。把Activity的View和Controller抽离出来就变成了View和Presenter,这就是MVP模式。

MVC模式
MVC模式的结构分为三部分,实体层的Model,视图层的View,以及控制层的Controller。
mvc模式

• 其中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模式的核心思想:

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);
}

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);

}

这些接口在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;
}

}

从以上可以看出 在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;
            }

…}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值