安卓MVP设计模式

一、概述
对于MVP设计模式,我相信大部分安卓开发者都应该听过,可到底MVP是怎么样的,或许很多人也没有实践过,今天,我就带大家走进MVP的使用。
1、MVP是什么?
Model-view-presenter,简称MVP,是软件设计中一种对针对MVC模式,再审议后所延伸提出的一种软件设计模式。
MVP的使用有助于实现程序结构分离,解耦。

Model 定义程序的业务逻辑和实体模型。
View 视图层,用以展示来自Model的信息以及经过Presenter对事件处理后的信息,对应于布局文件、Activity和Fragment。
Presenter 包含着事件逻辑处理,负责从Model层获取信息,并将取得的信息经过格式转换与View进行通讯。

2、MVP与MVC的区别
MVC
Model:定义程序的业务逻辑和实体模型。
View:视图层,对应于布局文件。
Controller:业务逻辑层,主要是Activity和Fragment。

MVC里View对应于布局文件,其实做的事情仅仅是展示控件,实际上数据绑定的操作,事件处理的代码都在Activity或Fragment中,造成了Activity或Fragment既承担了View的功能又承担了Controller的功能,MVC还允许Model与View进行交互。
而在MVP中,Presenter的出现,将Actvity/Fragment作为View层,Presenter负责完成View层与Model层的交互,这样做的好处是程序代码耦合度更低,更容易测试,结构更清晰。但随之也带来一个问题:类的数量过多,为了实现一个界面功能,相比传统MVC,你可能需要创建更多额外的类文件。

二、案例
本案例,我实现了一个请求网络新闻的功能。下面来介绍MVP在其中的应用。
包结构:
这里写图片描述

(1)Model层
News实体类,我是通过GsonFormat生成的

public class News {

    private String error_code;
    private String reason;
    private List<ResultBean> result;

    public String getErrorCode() {
        return error_code;
    }

    public void setErrorCode(String error_code) {
        this.error_code = error_code;
    }

    public String getReason() {
        return reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

    public List<ResultBean> getResult() {
        return result;
    }

    public void setResult(List<ResultBean> result) {
        this.result = result;
    }

    public static class ResultBean {

        private String title;
        private String content;
        private String img_width;
        private String full_title;
        private String pdate;
        private String src;
        private String img_length;
        private String img;
        private String url;
        private String pdate_src;

        public String getTitle() {
            return title;
        }

        public void setTitle(String title) {
            this.title = title;
        }

        public String getContent() {
            return content;
        }

        public void setContent(String content) {
            this.content = content;
        }

        public String getImg_width() {
            return img_width;
        }

        public void setImg_width(String img_width) {
            this.img_width = img_width;
        }

        public String getFull_title() {
            return full_title;
        }

        public void setFull_title(String full_title) {
            this.full_title = full_title;
        }

        public String getPdate() {
            return pdate;
        }

        public void setPdate(String pdate) {
            this.pdate = pdate;
        }

        public String getSrc() {
            return src;
        }

        public void setSrc(String src) {
            this.src = src;
        }

        public String getImg_length() {
            return img_length;
        }

        public void setImg_length(String img_length) {
            this.img_length = img_length;
        }

        public String getImg() {
            return img;
        }

        public void setImg(String img) {
            this.img = img;
        }

        public String getUrl() {
            return url;
        }

        public void setUrl(String url) {
            this.url = url;
        }

        public String getPdate_src() {
            return pdate_src;
        }

        public void setPdate_src(String pdate_src) {
            this.pdate_src = pdate_src;
        }
    }

}

获取新闻的逻辑接口INewsDao:

public interface INewsDao {
    void getNews(String key,OnDataGetListener listener);
}
public class NewsDaoImpl implements INewsDao {

    public static final String BASE_URL = " http://apis.haoservice.com/lifeservice/news?";
    public static final String APP_KEY = "6a74ccfde5e04f27b344718ba923fe3f";

    /**
     * 请求新闻数据的具体实现方法
     * @param keyWords  关键词
     * @param listener  请求结果回调接口
     */
    @Override
    public void getNews(String keyWords, final OnDataGetListener listener) {
        try {
            keyWords = URLEncoder.encode(keyWords, "utf-8");

            StringBuilder sb = new StringBuilder();
            sb.append(BASE_URL);
            sb.append("key=");
            sb.append(APP_KEY);
            sb.append("&q=");
            sb.append(keyWords);

            //创建一个请求
            final Request request = new Request.Builder().url(sb.toString()).build();
            //创建一个Call
            final Call call = HttpHelper.getInstance().getOkHttpClient().newCall(request);

            //执行请求
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    if (listener != null) {
                        listener.onError();
                    }
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    if (listener != null) {
                        listener.onSuccess(response.body().string());
                    }
                }
            });

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

网络请求采用OkHttp:

public class HttpHelper {

    private static HttpHelper mInstance;
    private static OkHttpClient mOkHttpClient;

    private HttpHelper() {
        //初始化OkHttpClient
        mOkHttpClient = new OkHttpClient().newBuilder()
                .connectTimeout(10, TimeUnit.SECONDS)//设置超时时间
                .readTimeout(10, TimeUnit.SECONDS)//设置读取超时时间
                .writeTimeout(10, TimeUnit.SECONDS)//设置写入超时时间
                .build();
    }

    public static HttpHelper getInstance() {
        if (mInstance == null) {
            synchronized (HttpHelper.class) {
                if (mInstance == null) {
                    mInstance = new HttpHelper();
                }
            }
        }
        return mInstance;
    }


    public OkHttpClient getOkHttpClient() {
        return mOkHttpClient;
    }

}

(2)View层
Presenter与View交互是通过接口。所以我们这里需要定义一个INewsView,通过里面的接口方法来执行对View的操作。

/**
 * 通用的View模块,可以在这里写一些公用的接口方法
 * @author king
 * @date 2017/3/10 10:23
 */
public interface IViewBinder {
}

//开发人员可以根据实际需求扩展该接口,增加其他操作View的方法。
public interface INewsView extends IViewBinder {
	
    void showProgress();//显示进度条

    void hideProgress();//隐藏进度条

    void onSuccess(String response);//请求成功

    void onError();//请求失败
}

作为View层,最重要的当然是Activity,MVP模式中Activity也是作为View层一部分。

public class MainActivity extends AppCompatActivity implements INewsView {

    private ProgressDialog mProgressDialog;

    private Button btn_get;
    private TextView tv_data;

    private NewsPresenter mNewsPresenter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        btn_get = (Button) findViewById(R.id.btn_get);
        tv_data = (TextView) findViewById(R.id.tv_data);

        mProgressDialog = new ProgressDialog(this);//创建进度加载框
        mProgressDialog.setMessage("加载中");
        mNewsPresenter = new NewsPresenter(this);//创建Presenter
        btn_get.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mNewsPresenter.getNews("三星电视变CIA窃听器");//触发网络请求
            }
        });
    }

	/**
	* 显示加载进度框
	*/
    @Override
    public void showProgress() {
        mProgressDialog.show();
    }

	/**
	* 隐藏加载进度框
	*/
    @Override
    public void hideProgress() {
        mProgressDialog.dismiss();
    }

	/**
	* 请求数据成功回调
	*/
    @Override
    public void onSuccess(String response) {
        try {
            News news = parseJson(response);
            String code = news.getErrorCode();
            if("0".equals(code)) {
                String text = news.getResult().get(0).getTitle()+"\n\n"+news.getResult().get(0).getContent();
                tv_data.setText(text);
            }else{
                Toast.makeText(this,news.getReason(),Toast.LENGTH_SHORT).show();
            }
        }catch (Exception e){


        }
    }

	/**
	* 请求数据失败回调
	*/
    @Override
    public void onError() {
        Toast.makeText(this,"请求数据失败",Toast.LENGTH_SHORT).show();
    }
    
	/**
	* 解析json
	*/
    private News parseJson(String json) {
        return new Gson().fromJson(json, News.class);
    }
}

(3)Presenter
Presenter用于处理Model与View的交互,类似MVC中的Controller层,数据获取到了,就应该展示在View。
首先定义一个IBasePresenter用来封装一些通用的方法,例如关联Activity的生命周期,在各个方法用户可以自己定义自己想要做的事。

/**
 * 基础的presenter,用于关联Activity或fragment生命周期
 * @author king
 * @date 2017/3/10 10:24
 */
public interface IBasePresenter {

    void onCreate();

    void onStart();

    void onPause();

    void onStop();

    void onDestory();
}
public class NewsPresenter implements IBasePresenter{

    private INewsView mNewsView;
    private NewsDaoImpl newsDao;
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case 200:
                    mNewsView.onSuccess((String) msg.obj);//因为是异步,所以需要handler
                    break;
                case 201:
                    mNewsView.onError();
                    break;
            }
        }
    };

    public NewsPresenter(INewsView view){
        this.mNewsView = view;
        this.newsDao = new NewsDaoImpl();
    }

    /**
     * 获取新闻数据
     * @param key
     */
    public void getNews(String key){
        mNewsView.showProgress();
        newsDao.getNews(key, new OnDataGetListener() {
            @Override
            public void onSuccess(String response) {
                mNewsView.hideProgress();
                Message msg = Message.obtain();
                msg.what = 200;
                msg.obj = response;
                mHandler.sendMessage(msg);
            }

            @Override
            public void onError() {
                mNewsView.hideProgress();
                Message msg = Message.obtain();
                msg.what = 201;
                mHandler.sendMessage(msg);
            }
        });

    }
    @Override
    public void onCreate() {

    }

    @Override
    public void onStart() {

    }

    @Override
    public void onPause() {

    }

    @Override
    public void onStop() {

    }

    @Override
    public void onDestory() {

    }
}

注意到,Presenter里面有Model层和View层 的实现类:NewsDaoImpl和INewsView,这就是Presenter的作用,从View中获取需要的数据,交给Model去执行业务方法,执行的过程中需要的反馈以及结果,让View进行对应的显示。

好了,完整的代码结构讲完了,大家可以在https://github.com/GdinKing/MVPDemo下载源码。
希望大家能对MVP有更深的认识。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猫King

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值