说到MVP肯定要先说下MVC,想必大家对android的MVC都有很深的了解。

View:布局文件,用于界面显示

Model:业务逻辑和实体模型

Controllor:对应于Activity,用于数据和界面的交互显示

20150622212835554

由上图可以看出,View与数据的关系错综复杂,即activity不仅要负责数据的加工还要负责对数据的显示工作。一旦业务逻辑复杂,代码的可读性会大大的下降。

MVP设计思想与MVC有很大的不同,它将数据加工和界面交互的工作分开来做,即增加Presenter 负责完成View于Model间的交互。

20150622212856011

这样一来,activity的代码量就会打打的下降。

接下来我们用一个简单的Demo来说明下:

下载Demo

下面就获取图片列表并显示在RecyclerView为例进行说明。

图片api使用的是新浪看见列表数据(声明:数据api仅用于学习交流)

api地址:
http://api.slide.news.sina.com.cn/interface/api_album_photo_col.php?app_key=1985696825&photo_col_id=10&tags=cat&tagmode=any&jsoncallback=get_witness_list&format=json&page=1&num=20&_=1458029148787

请求使用GET方式,大家可以根据需要更改里面的参数,如page和num等

该api返回数据的格式为get_witness_list(json),所以不能直接转换为对象,我们只需要去除()内的json数据即可,具体做法不再赘述,下面来具体实现。

1.domain实体类

有了api和返回的数据我们可以很快的建立其对应的实体类,android studio用户推荐使用GsonFormat。由于实体类的参数比较多,这里不再贴出,有兴趣的可以查看Demo

2.model数据层

ImageLsitModel,调用实现里面的接口回调,并且传入页码参数。

public interface ImageListModel {
    void getImageNewList(int    page,ImageListModelImpl.OnImageNewLoadListenter listenter);
}

ImageListModelImpl,实现ImageLsitModel,并且声明接口OnImageNewLoadListenter

当成时返回 image对象(就是是一个list),失败时返回错误的原因。

public interface OnLoadImageListener {
void onSuccess(HenuImage image);

void OnFaild(String str);

}

在实现ImageListModel的方法中完成数据的获取,你可以使用自己认为比较合理的方式来实现,如RxJava+Retrofit,为了方便大家理解mvp我们直接使用okhttp来实现。

package com.flyou.seen.flyouseen.ImageList.model;

import com.google.gson.Gson;
import com.flyou.seen.flyouseen.ImageList.domain.ImageNews;
import com.flyou.seen.flyouseen.comm.APi;
import com.zhy.http.okhttp.OkHttpUtils;
import com.zhy.http.okhttp.callback.StringCallback;

import java.util.List;

import okhttp3.Call;

/**
 * ============================================================
 * 项目名称:HotWXReading
 * 包名称:com.liuyajuan.login.hotwxreading.ImageList.model
 * 文件名:ImageListModelImpl
 * 类描述:
 * 创建人:flyou
 * 邮箱:fangjaylong@gmail.com
 * 创建时间:2016/3/15 15:36
 * 修改备注:
 * 版本:@version  V1.0
 * ============================================================
 **/
public class ImageListModelImpl implements ImageListModel {

    @Override
    public void getImageNewList(int page, final OnImageNewLoadListenter listenter) {
        OkHttpUtils
                .get()
                .url(APi.IMAGE_NEW_LIST_URL + "page=" + page)
                .build()
                .execute(new StringCallback() {
                    @Override
                    public void onError(Call call, Exception e) {
                        listenter.onFailed(e.getMessage(), e);
                    }

                    @Override
                    public void onResponse(String response) {
                        try {
                            String json = response.split("\\(")[1].split("\\)")[0];
                            ImageNews imageNews = new Gson().fromJson(json, ImageNews.class);
                            listenter.onSuccess(imageNews.getData());
                        }
                       catch (Exception e){

                       }

                    }
                });
    }

    public interface OnImageNewLoadListenter {
        void onSuccess(List<ImageNews.DataEntity> imageNews);
        void onFailed(String msg, Exception e);
    }
}

3.View 界面展示层

ImageNewsView,主要提供界面交互需要的接口,一般为:

showLoading();显示进入条等加载界面

hideLoading();隐藏进度条等

showloadFailed();显示加载错误界面

getImageNew(object obj)获取数据并显示

这次Demo的View如下:

public interface HenuImageView {
    void  showLoading();
    void  hideLoading();
    void  GetImage(HenuImage henuImage);
    void  showLoadFaild(String str);
}

4.Presenter层,负责View和Model的交互和调度

ImgaeNewPresenter

public interface ImgaeNewPresenter {
void  getImageList(int page);
}

ImageNewPresenterImpl

实现ImgaeNewPresenter和ImageListModelImpl.OnImageNewLoadListenter,在构造方法中完成View(activity实现) 和Model的初始化。

在getImageList()中loadingView可见,并且执行Modele层的数据获取操作

在onSuccess()中将loadingVeiw隐藏,并且将获取到的数据回调给view的实现类。

在onFailed()中将loadingVeiw隐藏,并且msg传给view的实现类。

public class ImageNewPresenterImpl implements ImgaeNewPresenter, ImageListModelImpl.OnImageNewLoadListenter {
    private ImageNewsView mImageNews;
    private ImageListModelImpl mImageListModel;
    public ImageNewPresenterImpl(ImageNewsView imageNews) {
        this.mImageListModel = new ImageListModelImpl();
        this.mImageNews = imageNews;

    }



    @Override
    public void getImageList(int page) {

        mImageNews.showLoading();
        mImageListModel.getImageNewList(page, this);
    }

    @Override
    public void onSuccess(List<ImageNews.DataEntity> imageNews) {
        mImageNews.hideLoading();
        mImageNews.addImage(imageNews);
    }

    @Override
    public void onFailed(String msg, Exception e) {
        mImageNews.hideLoading();
        mImageNews.shwoLoadFaild(msg);
    }
}

5.Activity 界面展示

实现View层的接口,初始化persenter,调用persenterimpl的方法完成数据的获取。

在activity中:

private ImgaeNewPresenter mImageNewPresenter;

public class MainActivity extends BaseActivity implements ImageNewsView{

@Override

onceate(){

初始化presenter

mImageNewPresenter = new ImageNewPresenterImpl(this);
mImageNewPresenter.getImageList(currentPage);

}

@Override
public void showLoading() {

//显示加载界面
loadingView.setVisibility(View.VISIBLE);
}

@Override
public void addImage(List<ImageNews.DataEntity> imageNewList) {

//界面展示
}

}
@Override
public void hideLoading() {
//隐藏加载界面
}

@Override
public void shwoLoadFaild() {

//显示获取数据错误界面
}

}

 

这样一个简单的mvp功能就实现,数据层和View层完全分开了,这样在进行单元测试时就很方便了。

总结:mvp实际上就是将以前activity中复杂的数据获取和传递的过程抽离了出来,让Model来完成,persenter负责view和model的交互和数据的传递,将数据和视图分割开来,互不干扰,是项目的结构更加的清晰。

有什么我写的不妥的地方,欢迎大家指正!