我理解的 MVP

上一篇文章中写了 MVC,Controller 层作为 View 层和 Model 层交互的链接,它从 View 层获取到用户输入交由 Model 层去处理,Model 层处理过后的数据又经过 Controller 层交由 View 层去显示。根据业务的不同,各层之间也存在着一定的耦合。

随着业务的增加,页面中 Controller 中的代码会逐渐增加,变得臃肿。于是 MVP 就产生并逐渐成为主流了。

什么是 MVP,和 MVC 有何不同?

和 MVC 一样,它同样也是将业务分为三层:

  • Model 层,和 MVC 一样,继续是页面的“功能”实现。
  • View 层,和 MVC 相差无几,只是将 Activity/Fragment 视作 View 层的一部分,而不像 MVC 当中 Activity/Fragment 被当作 Controller 一样,并且新增了 View 接口,用作和 Presenter 进行互动。
  • Presenter 层,工作原理和 Controller 类似,只是它不再和 View 层绑定,而是通过接口去操作 View,使得 View 可以独立存在,也方便单元测试。

该怎么写?

Model 就不用说了,原来咋写还咋写。

public class WeatherModelImpl implements IWeatherModel {
    @Override
    public void getWeather(String cityName, final OnWeatherListener listener) {
        String requestUrl = "https://free-api.heweather.com/s6/weather/now?location=" + cityName + "&key=5d520eb089e646acb********7e387";
        OkHttpClient client = new OkHttpClient();
        final Request request = new Request.Builder().url(requestUrl).build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                listener.getWeatherError(e.toString());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    String responseJson = response.body().string();
                    Gson gson = new Gson();
                    WeatherBean weatherArr = gson.fromJson(responseJson, WeatherBean.class);
                    String status = weatherArr.getHeWeather6().get(0).getStatus();
                    if ("ok".equals(status)) {
                        listener.getWeatherSuccess(weatherArr.getHeWeather6().get(0).getBasic().getLocation() + " 的天气是 " + weatherArr.getHeWeather6().get(0).getNow().getCond_txt());
                    } else {
                        listener.getWeatherError("查询出错:" + status);
                    }
                }
            }
        });
    }
}

View 层上面说过了,是将 Activity/Fragment 作为 View 层,并且新增了 View 接口,来和 Presenter 进行互动。

这个接口是干啥的呢?通俗点儿说就是,你这个页面需要干啥,你就得在这个接口中定义啥。例如你需要在页面当中显示一个 dialog,你就得定一个 showDailog 方法,同时也需要一个 dismissDailog 方法,你需要显示动画,自然也就需要一个 startAnimator 和 stopAnimator 方法了。这个根据你的页面功能自己去定义。

多说无益,上代码,还是 MVC 当中那个获取天气的例子。

View Interface:

public interface IWeatherView {
    void showWeather(String result);

    void showError(String error);
}

View

public class MainActivity extends AppCompatActivity implements View.OnClickListener, IWeatherView {

    private Button btnSearch;
    private TextView textWeather;
    private EditText editCity;
    private WeatherPrecenter precenter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        precenter = new WeatherPrecenter(this);
        btnSearch = findViewById(R.id.btn_search);
        textWeather = findViewById(R.id.text_weather);
        editCity = findViewById(R.id.edit_city);

        btnSearch.setOnClickListener(this);

    }

    @Override
    public void onClick(View v) {
        precenter.search(editCity.getText().toString());
    }

    @Override
    public void showWeather(String result) {
        Message msg = new Message();
        msg.obj = result;
        handler.sendMessage(msg);
    }

    @Override
    public void showError(String error) {
        Message msg = new Message();
        msg.obj = error;
        handler.sendMessage(msg);
    }

    Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            textWeather.setText((String) msg.obj);
        }
    };
}

在 MVP 模式当中,我们将 Activity/Fragment 作为 View,然后通过一个接口和外接发生交互。

Precenter 层

public class WeatherPrecenter implements OnWeatherListener {
    private IWeatherView view;
    private WeatherModelImpl model;

    public WeatherPrecenter(IWeatherView view) {
        this.view = view;
        model = new WeatherModelImpl();
    }

    public void search(String cityName) {
        model.getWeather(cityName, this);
    }

    @Override
    public void getWeatherSuccess(String result) {
        view.showWeather(result);
    }

    @Override
    public void getWeatherError(String result) {
        view.showError(result);
    }
}

监听器

public interface OnWeatherListener {
    void getWeatherSuccess(String result);

    void getWeatherError(String result);
}

总结

其实不管是 MVC 还是 MVP,都是将我们的页面分为几层,相互解耦,然后每层各司其职。

在 MVC 当中 Activity/Fragment 作为 Controller 来控制 Model 和 View 之间的交互。

在 MVP 当中,Activity/Fragment 作为 View 层,并且提供了一个对外的接口,View 层通过该接口和外接进行交互,而另外设置一个 Precenter 角色,用来主持 Model 和 View 之间的交互。

这样做的好处在于 View 层更加独立出来,它不用再去和 Model 层产生交互,Model 层只专注业务处理,View 层只专注接受/显示数据,他们两层之间的交互交由 Precenter 去处理。

缺点自然就是接口类爆发,会增长开发时间。

Copyright© 2020-2022 li-xyz 冀ICP备2022001112号-1