MVP在Android中简易易懂的实现案例

    xiaoxiao2021-03-25  111

    前言

    最进想做了一个新的小项目,总想来点对自己来说新鲜的东西。后面看到Google老大推荐使用MVP架构,顿时觉得不试试看都不好说是羡慕它的小弟了。良心大哥也专门在Github推出了一个项目Android Architecture Blueprints,用来展示Android用各种的MVP框架,也能算了官网教程了。在网络收集资料看了一下大神们的分析后,自己动手试了试。那么就马上上手来看一看MVP究竟如何。(本文都是围绕项目中todo-mvp部分来介绍 )

    MVP模式

    先上一张图,然后根据实际的代码我们来讲讲Google是怎么看待MVP架构的

    基类

    首先丁一两个Base接口,分别是作为Presenter和View的基类 public interface BaseView<T> { // 为View设置Presenter void setPresenter(T presenter); // 初始化界面控件 void initView(View view); } public interface BasePresenter { // 获取数据并改变界面显示,在todo-mvp的项目中的调用时机为Fragment的OnResume()方法中 void start(); }

    契约类

    官方事例中加如契约类来统一管理View和Presenter。这样整个功能可以在契约类一目了然。老大就是老大,这一点还是很厉害的。事例如下:

    public interface YourContract { interface View extends BaseView<Presenter>{ //这里加View功能方法 void showError(); void showLoading(); void Stoploading(); } interface Presenter extends BasePresenter{ // 同上 void loatPosts(int PagerNum,boolean cleaing); void reflush(); void loadMore(int PagerNum); } } </java> 对了,其中BaseView中含方法setPresenter,该方法作用是在将presenter实例传入view中,其调用时机是presenter实现类的构造函数中。如下 <java> public YourPresenter(Context context, YourContract.View view) { this.context=context; this.view=view; this.view.setPresenter(this); }

    Activity的作用

    在讲这个之前,不知道大家有没有注意到上没图中,Fragment是作为View层而Activity是作为Presenter的,有没有想过Google为什么要推荐这样做呢?

    MVC中Activity的作用

    按照我们之前的习惯或者说在MVC模式中,Activity是作为View层和用户打交道,接收用户数据的输入和输出的。特别是我们会在Activity的声明周期中写入一些逻辑来实现我们想要的效果。这样很方便,但是后果是我们的Activity特别的臃肿,想一想如果我们一些通用的功能每个Activity里都要写一次不是一件很痛苦的事情。 这个时候,Activity 不仅承担了 View 的角色,还承担了一部分的 Controller 角色,这样一来 V 和 C 就耦合在一起了,虽然这样写方便,但是如果业务调整的话,要维护起来就难了,而且在一个臃肿的 Activity 类查找业务逻辑的代码也会非常蛋疼,所以看起来有必要在 Activity 中,把 View 和 Controller 抽离开来,而这就是 MVP 模式的工作了。

    MVP中View层的实现

    至于为什么要选择Fragment作为View层的实现类。我看到网上有这两种说法,第一个原因是我们把activity作为一个全局控制类来创建对象,把fragment作为view,这样两者就能各司其职。第二个原因是因为fragment比较灵活,能够方便的处理界面适配的问题

    MVP 把 Activity 中的 UI 逻辑抽象成 View 接口,把业务逻辑抽象成 Presenter 接口,Model 类还是原来的 Model。

    来看一段代码就能知道Activity的作用了(毕竟代码能够一目了然):

    @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); if (savedInstanceState!=null){ mainFragment= (MainFragment) getSupportFragmentManager().getFragment(savedInstanceState,"MainFragment"); bookmarksfragment=(BookmarksFragment) getSupportFragmentManager().getFragment(savedInstanceState,"BookmarksFragment"); }else { mainFragment=MainFragment.newInstance(); bookmarksfragment=BookmarksFragment.newInstance(); } new BookmarksPresenter(MainActivity.this,bookmarksfragment); } 看了上面的代码大概就能知道Activity的作用是什么了。主要是作为全局的控制,负责创建View以及Presenter实例,并将二者联系起来。

    View层的实现

    ““ public class YourFragment extends Fragment implements YourContract.View { private YourContract.Presenter presenter; @Override public void onResume() { super.onResume(); presenter.start(); } @Override public void setPresenter(YourContract.Presenter presenter) { if (presenter!=null){ this.presenter=presenter; } } @Override public void showError() { Snackbar.make(fab, R.string.loaded_failed,Snackbar.LENGTH_INDEFINITE) .setAction(R.string.retry, new View.OnClickListener() { @Override public void onClick(View v) { presenter.reflush(); } }) .show(); }

    @Override public void showLoading() { refresh.post(new Runnable() { @Override public void run() { refresh.setRefreshing(true); } }); } @Override public void Stoploading() { refresh.post(new Runnable() { @Override public void run() { refresh.setRefreshing(false); } }); } } ““ 可以看到通过setPresenter方法获取到Presenter的实例。然后在Fragment的生命周期中调用presenter.start()方法。这样View层只负责数据给用户呈现他们看到的东西,而不去管具体是怎样实现的(ps:我觉得在onResume()方法之前调用应该都行吧,不知道是不是对的。如果有错,还请指教)

    Presenter层的实现

    ““ public class YourPresenter implements YourContract.Presenter { public YourPresenter(Context context, YourContract.View view) { this.context=context; this.view=view; this.view.setPresenter(this); }

    @Override public void loatPosts(int PagerNum, final boolean cleaing) { //具体实现就不贴了,有点长 } @Override public void start() { loatPosts(CurrentPagerNum,true); }

    @Override public void reflush() { loatPosts(CurrentPagerNum,true); }

    @Override public void loadMore(int PagerNum) { loatPosts(CurrentPagerNum+PagerNum,false); } } ““ 在构造方法中,Presenter将自身的事例传递给了View,这样View就能调用Presenter层的方法来处理业务逻辑了。在start()方法中,处理了数据加载。

    Model层的实现

    项目中model层最大的特点是被赋予了数据获取的职责,与我们平常model层只定义实体对象截然不同,实例中,数据的获取、存储、数据状态变化都是model层的任务,Presenter会根据需要调用该层的数据处理逻辑并在需要时将回调传入。这样model、presenter、view都只处理各自的任务,此种实现确实是单一职责最好的诠释。

    总结

    MVP的好处

    分离了视图逻辑和业务逻辑,降低耦合度,实现了Model和View真正的完全分离,可以修改View而不影响ModleActivity 只处理生命周期的任务,代码变得更加简洁视图逻辑和业务逻辑分别抽象到了 View 和 Presenter 的接口中去,提高代码的可阅读性View可以进行组件化。在MVP当中,View不依赖Model。这样就可以让View从特定的业务场景中脱离出来,可以说View可以做到对业务完全无知。它只需要提供一系列接口提供给上层操作。这样就可以做到高度可复用的View组件。利于测试驱动开发。Presenter 被抽象成接口,可以有多种具体的实现,所以方便进行单元测试。在使用MVP的项目中Presenter对View是通过接口进行,在对Presenter进行不依赖UI环境的单元测试的时候。可以通过Mock一个View对象,这个对象只需要实现了View的接口即可。然后依赖注入到Presenter中,单元测试的时候就可以完整的测试Presenter应用逻辑的正确性。

    以上就是我这段时间来对MVP的理解了。如果有错误的地方,欢迎指教哦。

    转载请注明原文地址: https://ju.6miu.com/read-5247.html

    最新回复(0)