Android MVP学习

本文介绍了MVP(Model-View-Presenter)设计模式的概念及其在实际项目中的应用案例。MVP模式通过将模型、视图和主持人分离,降低各部分间的耦合度,便于独立开发和测试。文章以获取天气信息为例,详细展示了MVP模式的具体实现。

一.概述

首先来介绍一下什么是MVP
MVP是模型(Model)、视图(View)、主持人(Presenter)的缩写,分别代表项目中3个不同的模块。
  模型(Model):负责处理数据的加载或者存储,比如从网络或本地数据库获取数据等;
  视图(View):负责界面数据的展示,与用户进行交互;
  主持人(Presenter):相当于协调者,是模型与视图之间的桥梁,将模型与视图分离开来。
  如下图所示,View与Model并不直接交互,而是使用Presenter作为View与Model之间的桥梁。其中Presenter中同时持有Viwe层以及Model层的Interface的引用,而View层持有Presenter层Interface的引用。当View层某个界面需要展示某些数据的时候,首先会调用Presenter层的某个接口,然后Presenter层会调用Model层请求数据,当Model层数据加载成功之后会调用Presenter层的回调方法通知Presenter层数据加载完毕,最后Presenter层再调用View层的接口将加载后的数据展示给用户。这就是MVP模式的整个核心过程。
  这里写图片描述

 这样分层的好处就是大大减少了Model与View层之间的耦合度。一方面可以使得View层和Model层单独开发与测试,互不依赖。另一方面Model层可以封装复用,可以极大的减少代码量。当然,MVP还有其他的一些优点,这里不再赘述。下面看下MVP模式在具体项目中的使用。 这样分层的好处就是大大减少了Model与View层之间的耦合度。一方面可以使得View层和Model层单独开发与测试,互不依赖。另一方面Model层可以封装复用,可以极大的减少代码量。当然,MVP还有其他的一些优点,这里不再赘述。下面看下MVP模式在具体项目中的使用。

二.MVP在项目中的应用

下面以一个请求天气信息的例子来看一下MVP的具体应用。
先看效果图

这里写图片描述

1.View层
天气信息模块主要展示从网络获取到的天气信息,View层的接口大概需要如下方法:
(1)显示正在加载数据的进度条
(2)请求成功隐藏进度条
(3)失败显示错误信息
(4)设置获取到的天气信息

public interface WeatherView {
    void showLoading();
    void hideLoading();
    void showError();
    void setWeatherInfo(Call<WeatherInfo> call, Response<WeatherInfo> response);
}

在信息展示页面实现这个接口

public class MainActivity extends AppCompatActivity implements WeatherView {
    @Bind(R.id.et_citynumber)
    EditText mEtCitynumber;
    @Bind(R.id.textview)
    TextView mTextview;
    Dialog dialog;
    //View层持有presenter层的引用
    private WeatherPresenterImpl mWeatherPresenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        dialog = new ProgressDialog(this);
        dialog.setTitle("正在加载中");
        mWeatherPresenter = new WeatherPresenterImpl(this);
    }
    public void click(View view){
        String number = mEtCitynumber.getText().toString();
        mWeatherPresenter.getWeatherInfo(number);
    }

    @Override
    public void showLoading() {
        dialog.show();
    }

    @Override
    public void hideLoading() {
        dialog.dismiss();
    }

    @Override
    public void showError() {
        Toast.makeText(this, "error", Toast.LENGTH_SHORT).show();
    }

    /**
     * 获取数据成功后会调用此方法,此方法的调用处在presentImpl的onResponse方法里
     * @param call
     * @param response
     */
    @Override
    public void setWeatherInfo(Call<WeatherInfo> call, Response<WeatherInfo> response) {
        WeatherInfo weatherInfo = response.body();
        mTextview.setText(weatherInfo.toString());
    }
}

2.Model层
model层主要负责从网络获取数据,model接口如下

/**
 * 抽象模型,定义了访问数据的方法,方法中持有presenter一个接口的引用,目的就是为了方便回调
 */
public interface WeatherModel {
    void loadWeather(String cityId, OnWeatherListener weatherListener);
}

model接口的实现如下

/**
 * 模型的实现类,具体对数据进行操作
 */
public class WeatherModelImpl implements WeatherModel {
    @Override
    public void loadWeather(String cityId, final OnWeatherListener weatherListener) {
        DemoApi demoApi = RetrofitWrapper.getInstance().create(DemoApi.class);
        Call<WeatherInfo> weatherInfo = demoApi.getWeatherInfo(cityId);
        weatherInfo.enqueue(new Callback<WeatherInfo>() {
            @Override
            public void onResponse(Call<WeatherInfo> call, Response<WeatherInfo> response) {
            //通过weatherListener回调将Modle层处理好的数据交给Presenter层
                weatherListener.onResponse(call,response);
            }

            @Override
            public void onFailure(Call<WeatherInfo> call, Throwable t) {
                weatherListener.onFailure(call,t);
            }
        });
    }
}

3.presenter层
View层需要调用presenter层获取数据,所以presenter层要提供一个接口

public interface WeatherPresenter {
    /**
     * 获取天气的信息,
     * @param cityId
     */
    void getWeatherInfo(String cityId);
}

同时要提供一个接口给Modle层回调

public interface OnWeatherListener {
    /**
     * 在presenter层实现,给Model层回调,更改view的状态,确保model层不直接操作view层
     * @param call
     * @param response
     */
    void onResponse(Call<WeatherInfo> call, Response<WeatherInfo> response);
    void onFailure(Call<WeatherInfo> call, Throwable t);
}

在presentImple的构造方法中,我们传进来一个View层的对象,同时创建一个modelImpl的对象,目的就是为了调用获取数据的方法。


/**
 * 实现了接口,给View层回调
 */
public class WeatherPresenterImpl implements WeatherPresenter,OnWeatherListener{
    /**
     * presenter层持有model层和view层的引用
     */
    private WeatherModelImpl mWeatherModelImpl;
    private WeatherView mWeatherView;

    /**
     * 此方法在View层调用
     * @param weatherView
     */
    public WeatherPresenterImpl(WeatherView weatherView){
        this.mWeatherView = weatherView;
        mWeatherModelImpl = new WeatherModelImpl();
    }

    /**
     * 此方法在view层调用
     * @param cityId
     */
    @Override
    public void getWeatherInfo(String cityId) {
        mWeatherView.showLoading();
        //model层获取数据
        mWeatherModelImpl.loadWeather(cityId,this);
    }

    /**
     * model层请求成功后会回调此方法
     * @param call
     * @param response
     */
    @Override
    public void onResponse(Call<WeatherInfo> call, Response<WeatherInfo> response) {
        mWeatherView.hideLoading();
        mWeatherView.setWeatherInfo(call,response);
    }
    /**
     * model层请失败后会回调此方法
     * @param call
     * @param response
     */
    @Override
    public void onFailure(Call<WeatherInfo> call, Throwable t) {
        mWeatherView.hideLoading();
        mWeatherView.showError();
    }
}

最后给出代码下载地址
点此下载源码

基于模拟退火的计算器 在线运行 访问run.bcjh.xyz。 先展示下效果 https://pan.quark.cn/s/cc95c98c3760 参见此仓库。 使用方法(本地安装包) 前往Releases · hjenryin/BCJH-Metropolis下载最新 ,解压后输入游戏内校验码即可使用。 配置厨具 已在2.0.0弃用。 直接使用白菜菊花代码,保留高级厨具,新手池厨具可变。 更改迭代次数 如有需要,可以更改 中39行的数字来设置迭代次数。 本地编译 如果在windows平台,需要使用MSBuild编译,并将 改为ANSI编码。 如有条件,强烈建议这种本地运行(运行可加速、可多次重复)。 在 下运行 ,是游戏中的白菜菊花校验码。 编译、运行: - 在根目录新建 文件夹并 至build - - 使用 (linux) 或 (windows) 运行。 最后在命令行就可以得到输出结果了! (注意顺序)(得到厨师-技法,表示对应新手池厨具) 注:linux下不支持多任务选择 云端编译已在2.0.0弃用。 局限性 已知的问题: - 无法得到最优解! 只能得到一个比较好的解,有助于开阔思路。 - 无法选择菜品数量(默认拉满)。 可能有一定门槛。 (这可能有助于防止这类辅助工具的滥用导致分数膨胀? )(你问我为什么不用其他语言写? python一个晚上就写好了,结果因为有涉及json读写很多类型没法推断,jit用不了,算这个太慢了,所以就用c++写了) 工作原理 采用两层模拟退火来最大化总能量。 第一层为三个厨师,其能量用第二层模拟退火来估计。 也就是说,这套方法理论上也能算厨神(只要能够在非常快的时间内,算出一个厨神面板的得分),但是加上厨神的食材限制工作量有点大……以后再说吧。 (...
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值