安卓常见架构之——mvp

综述

  对于MVP (Model View Presenter)架构是从著名的MVC(Model View Controller)架构演变而来的。而对于Android应用的开发中本身可视为一种MVC架构。通常在开发中将XML文件视为MVC中的View角色,而将Activity则视为MVC中的Controller角色。不过更多情况下在实际应用开发中Activity不能够完全充当Controller,而是Controller和View的合体。于是Activity既要负责视图的显示,又要负责对业务逻辑的处理。这样在Activity中代码达到上千行,甚至几千行都不足为其,同时这样的Activity也显得臃肿不堪。所以对于MVC架构并不很合适运用于Android的开发中。下面就来介绍一下MVP架构以及看一下google官方给出的MVP架构示例。

MVP架构简介

  对于一个应用而言我们需要对它抽象出各个层面,而在MVP架构中它将UI界面和数据进行隔离,所以我们的应用也就分为三个层次。

  • View: 对于View层也是视图层,在View层中只负责对数据的展示,提供友好的界面与用户进行交互。在Android开发中通常将Activity或者Fragment作为View层。
  • Model: 对于Model层也是数据层。它区别于MVC架构中的Model,在这里不仅仅只是数据模型。在MVP架构中Model它负责对数据的存取操作,例如对数据库的读写,网络的数据的请求等。
  • Presenter:对于Presenter层他是连接View层与Model层的桥梁并对业务逻辑进行处理。在MVP架构中Model与View无法直接进行交互。所以在Presenter层它会从Model层获得所需要的数据,进行一些适当的处理后交由View层进行显示。这样通过Presenter将View与Model进行隔离,使得View和Model之间不存在耦合,同时也将业务逻辑从View中抽离。

      下面通过MVP结构图来看一下MVP中各个层次之间的关系。 

      在MVP架构中将这三层分别抽象到各自的接口当中。通过接口将层次之间进行隔离,而Presenter对View和Model的相互依赖也是依赖于各自的接口。这点符合了接口隔离原则,也正是面向接口编程。在Presenter层中包含了一个View接口,并且依赖于Model接口,从而将Model层与View层联系在一起。而对于View层会持有一个Presenter成员变量并且只保留对Presenter接口的调用,具体业务逻辑全部交由Presenter接口实现类中处理。

官方MVP架构分析

项目介绍

  对于MVP架构有了一些的了解,而在前端时间Google给出了一些App开发架构的实现。 
  项目地址为:https://github.com/googlesamples/android-architecture
  在这里进入README看一下这次Google给出那些Android开发架构的实现。


  对于上面五个开发架构的实现表示到目前为止是已经完成的项目,而下面两个则表示正在进行的中的项目。现在首先来介绍一下这几个架构。

    • todo-mvp: 基础的MVP架构。
    • todo-mvp-loaders:基于MVP架构的实现,在获取数据的部分采用了loaders架构。
    • todo-mvp-databinding: 基于MVP架构的实现,采用了数据绑定组件。
    • todo-mvp-clean: 基于MVP架构的clean架构的实现。
    • todo-mvp-dagger2: 基于MVP架构,采用了依赖注入dagger2。
    • dev-todo-mvp-contentproviders: 基于mvp-loaders架构,使用了ContenPproviders。
    • dev-todo-mvp-rxjava: 基于MVP架构,对于程序的并发处理和数据层(MVP中的Model)的抽象。

        从上述的介绍中可以看出,对于官方给出所有的架构的实现最终都是基于MVP架构。所以在这里就对上面的基础的MVP架构todo-mvp进行分析。

      项目结构的分析

        对于这个项目,它实现的是一个备忘录的功能。对于工作中未完成的任务添加到待办任务列表中。我们能够在列表中可以对已完成的任务做出标记,能够进入任务详细页面修改任务内容,也能够对已完成的任务和未完成的任务数量做出统计。 
        首先在这里来看一下todo-mvp整体的项目结构 

        从上图中可以看出,项目整体包含了一个app src目录,四个测试目录。在src目录下面对代码的组织方式是按照功能进行划分。在这个项目中包含了四个功能,它们分别是:任务的添加编辑(addedittask),任务完成情况的统计(statistics),任务的详情(taskdetail),任务列表的显示(tasks)。对于data包它是项目中的数据源,执行数据库的读写,网络的请求操作都存放在该包内,也是MVP架构中的Model层。而util包下面则是存放一些项目中使用到的工具类。在最外层存放了两接口BasePresenter和BaseView。它们是Presenter层接口和View层接口的基类,项目中所有的Presenter接口和View层接口都继承自这两个接口。 
        现在进入功能模块内看下在模块内部对类是如何划分的。在每个功能模块下面将类分作xxActivity,xxFragment,xxPresenter,xxContract。也正是这些类构成了项目中的Presenter层与View层。下面就来分析在这个项目中是如何实现MVP架构。

      MVP架构的实现

        在这里只从宏观上关注MVP架构的实现,对于代码的内部细节在就不在具体分析。那么就以任务的添加和编辑这个功能来看一下Android官方是如何实现MVP架构。

      Model层的实现

        首先我们从MVP架构的最内层开始分析,也就是对应的Model层。在这个项目中对应的data包下的内容。在data下对数据库等一些数据源的封装。对于Presenter层提供了TasksDataSource接口。在这里看一下这个TasksDataSource接口。

    • public interface TasksDataSource {
      
          interface LoadTasksCallback {
      
              void onTasksLoaded(List<Task> tasks);
      
              void onDataNotAvailable();
          }
      
          interface GetTaskCallback {
      
              void onTaskLoaded(Task task);
      
              void onDataNotAvailable();
          }
      
          void getTasks(@NonNull LoadTasksCallback callback);
      
          void getTask(@NonNull String taskId, @NonNull GetTaskCallback callback);
      
          void saveTask(@NonNull Task task);
      
          ......
      }
      

        TasksDataSource接口的实现是TasksLocalDataSource,在TasksDataSource中的方法也就是一些对数据库的增删改查的操作。而在TasksDataSource的两个内部接口LoadTasksCallback和GetTaskCallback是Model层的回调接口。它们的真正实现是在Presenter层。对于成功获取到数据后变或通过这个回调接口将数据传递Presenter层。同样,若是获取失败同样也会通过回调接口来通知Presenter层。下面来看一下TasksDataSource的实现类。

    • public class TasksLocalDataSource implements TasksDataSource {
      
          ......
      
          @Override
          public void getTask(@NonNull String taskId, @NonNull GetTaskCallback callback) {
      
              //根据taskId查训出相对应的task
              ......
      
              if (task != null) {
                  callback.onTaskLoaded(task);
              } else {
                  callback.onDataNotAvailable();
              }
          }
      
          @Override
          public void saveTask(@NonNull Task task) {
              checkNotNull(task);
              SQLiteDatabase db = mDbHelper.getWritableDatabase();
      
              ContentValues values = new ContentValues();
              values.put(TaskEntry.COLUMN_NAME_ENTRY_ID, task.getId());
              values.put(TaskEntry.COLUMN_NAME_TITLE, task.getTitle());
              values.put(TaskEntry.COLUMN_NAME_DESCRIPTION, task.getDescription());
              values.put(TaskEntry.COLUMN_NAME_COMPLETED, task.isCompleted());
      
              db.insert(TaskEntry.TABLE_NAME, null, values);
      
              db.close();
          }
      
          ......
      }
      

        

      在这里我们针对任务的添加和编辑功能,所以省略很多代码。可以看出在TasksLocalDataSource中实现的getTask方法,在这个方法中传入TasksDataSource内的GetTaskCallback回调接口。在getTask方法的实现可以看出在查询到Task以后调用回调方法,若是在Presenter层中实现了这两个回调方法,便将数据传递到Presenter层。而对于查询到的Task为空的时候也是通过回调方法执行对应的操作。 
        同样对于通过网络请求获取到数据也是一样,对于成功请求到的数据可以通过回调方法将数据传递到Presenter层,对于网络请求失败也能够通过回调方法来执行相对应的操作。

      Presenter与View层提供的接口

        由于在Presenter和View层所提供的接口在一个类中,在这里就先来查看他们对外所提供了哪些接口。首先观察一下两个基类接口BasePresenter和BaseView。

      BasePresenter

    • package com.example.android.architecture.blueprints.todoapp;
      
      public interface BasePresenter {
      
          void start();
      
      }
      

        

      在BasePresenter中只存在一个start方法。这个方法一般所执行的任务是在Presenter中从Model层获取数据,并调用View接口显示。这个方法一般是在Fragment中的onResume方法中调用。

      BaseView

    • package com.example.android.architecture.blueprints.todoapp;
      
      public interface BaseView<T> {
      
          void setPresenter(T presenter);
      
      }
      

        

       在BaseView中只有一个setPresenter方法,对于View层会存在一个Presenter对象。而setPresenter正是对View中的Presenter进行初始化。

      AddEditTaskContract

        在Android官方给出的MVP架构当中对于Presenter接口和View接口提供的形式与我们平时在网上所见的有所不同。在这里将Presenter中的接口和View的接口都放在了AddEditTaskContract类里面。这样一来我们能够更清晰的看到在Presenter层和View层中有哪些功能,方便我们以后的维护。下面就来看一下这个AddEditTaskContract类。

    • public interface AddEditTaskContract {
      
          interface View extends BaseView<Presenter> {
      
              void showEmptyTaskError();
      
              void showTasksList();
      
              void setTitle(String title);
      
              void setDescription(String description);
      
              boolean isActive();
          }
      
          interface Presenter extends BasePresenter {
      
              void createTask(String title, String description);
      
              void updateTask( String title, String description);
      
              void populateTask();
          }
      }
      

        

      在这里很清晰的可以看出在View层中处理了一些数据显示的操作,而在Presenter层中则是对Task保存,更新等操作。

      Presenter层的实现

        下面就来看一下在Presenter是如何实现的。

    • public class AddEditTaskPresenter implements AddEditTaskContract.Presenter,
              TasksDataSource.GetTaskCallback {
      
          ......
      
          public AddEditTaskPresenter(@Nullable String taskId, @NonNull TasksDataSource tasksRepository,
                  @NonNull AddEditTaskContract.View addTaskView) {
              mTaskId = taskId;
              mTasksRepository = checkNotNull(tasksRepository);
              mAddTaskView = checkNotNull(addTaskView);
      
              mAddTaskView.setPresenter(this);
          }
      
          @Override
          public void start() {
              if (mTaskId != null) {
                  populateTask();
              }
          }
      
          ......
      
          @Override
          public void populateTask() {
              if (mTaskId == null) {
                  throw new RuntimeException("populateTask() was called but task is new.");
              }
              mTasksRepository.getTask(mTaskId, this);
          }
      
          @Override
          public void onTaskLoaded(Task task) {
              // The view may not be able to handle UI updates anymore
              if (mAddTaskView.isActive()) {
                  mAddTaskView.setTitle(task.getTitle());
                  mAddTaskView.setDescription(task.getDescription());
              }
          }
          ......
      }
      

        

       在这里可以看到在AddEditTaskPresenter中它不仅实现了自己的Presenter接口,也实现了GetTaskCallback的回调接口。并且在Presenter中包含了Model层TasksDataSource的对象mTasksRepository和View层AddEditTaskContract.View的对象mAddTaskView。于是整个业务逻辑的处理就担负在Presenter的身上。 
        从Presenter的业务处理中可以看出,首先调用Model层的接口getTask方法,通过TaskId来查询Task。在查询到Task以后,由于在Presenter层中实现了Model层的回调接口GetTaskCallback。这时候在Presenter层中就通过onTaskLoaded方法获取到Task对象,最后通过调用View层接口实现了数据的展示。

      View层的实现

        对于View的实现是在Fragment中,而在Activity中则是完成对Fragment的添加,Presenter的创建操作。下面首先来看一下AddEditTaskActivity类。

    • public class AddEditTaskActivity extends AppCompatActivity {
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.addtask_act);
      
              ......
      
              if (addEditTaskFragment == null) {
                  addEditTaskFragment = AddEditTaskFragment.newInstance();
                  ......
                  ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),
                          addEditTaskFragment, R.id.contentFrame);
              }
      
              // Create the presenter
              new AddEditTaskPresenter(
                      taskId,
                      Injection.provideTasksRepository(getApplicationContext()),
                      addEditTaskFragment);
          }
      
          ......
      }
      

        对于Activity的提供的功能也是非常的简单,首先创建Fragment对象并将其添加到Activity当中。之后创建Presenter对象,并将Fragment也就是View传递到Presenter中。 
        下面再来看一下View的实现,也就是Fragment。

    • public class AddEditTaskFragment extends Fragment implements AddEditTaskContract.View {
      
          ......
      
          @Override
          public void onResume() {
              super.onResume();
              mPresenter.start();
          }
      
          @Override
          public void setPresenter(@NonNull AddEditTaskContract.Presenter presenter) {
              mPresenter = checkNotNull(presenter);
          }
      
          ......
      
          @Override
          public void setTitle(String title) {
              mTitle.setText(title);
          }
      
          ......
      }

      在这对于源码就不在过多贴出。在Fragment中,通过setPresenter获取到Presenter对象。并通过调用Presenter中的方法来实现业务的处理。而在Fragment中则只是对UI的一些操作。这样一来对于Fragment类型的代码减少了很多,并且逻辑更加清晰。 
        我们注意到View层的实现是通过Fragment来完成的。对于View的实现为什么要采用Fragment而不是Activity。来看一下官方是如何解释的。

    •  The separation between Activity and Fragment fits nicely with this implementation of MVP: the Activity is the overall controller that creates and connects views and presenters.
      Tablet layout or screens with multiple views take advantage of the Fragments framework.
      

        

      在这里官方对于采用Fragment的原因给出了两种解释。

      • 通过Activity和Fragment分离非常适合对于MVP架构的实现。在这里将Activity作为全局的控制者将Presenter于View联系在一起。
      • 采用Fragment更有利于平板电脑的布局或者是多视图屏幕。

      总结

        通过MVP架构的使用可以看出对于各个层次之间的职责更加单一清晰,同时也很大程度上降低了代码的耦合度。对于官方MVP架构示例,google也明确表明对于他们所给出的这些架构示例只是作为参考,而不是一个标准。所以对于基础的MVP架构有更大的扩展空间。例如综合google给出的示例。我们可以通过在MVP架构的基础上使用dagger2,rxJava等来构建一个Clean架构。也是一个很好的选择。

  • 声明:此文章转载http://blog.csdn.net/ljd2038/article/details/51477475
时间: 2024-10-29 00:34:47

安卓常见架构之——mvp的相关文章

【转载】安卓APP架构

注:本篇博文转载于 http://my.oschina.net/mengshuai/blog/541314?fromerr=z8tDxWUH 本文介绍了文章作者从事了几年android应用的开发,经历2次架构变革,第一次集成了RxJava第二次集成了MVP,并将RxJava与MVP完美结合,实现了低耦合,代码简单,测试方便的架构. 其实我们在开发中也遇到过,Android入门门槛较低,如果前期对APP规划不清晰,Coder们对未来变化把握不准,技术架构经验不够强大,最终导致就是一个Activit

软件体系结构---安卓系统架构之应用程序框架层分析---1

本博客只介绍安卓系统架构中的应用程序框架层 什么是应用程序框架? 应用程序框架可以说是一个应用程序的核心,是所有参与开发的程序员共同使用和遵守的约定,大家在其约定上进行必要的扩展,但程序始终保持主体结构的一致性.其作用是让程序保持清晰和一目了然,在满足不同需求的同时又不互相影响. 而对于安卓来说:Android系统提供给应用开发者的本身就是一个框架,所有的应用开发都必须遵守这个框架的原则.我们在开发应用时就是在这个框架上进行扩展.在这个框架中我们可以完全访问核心应用程序所使用的API框架,即我们

[转]MVVM架构~mvc,mvp,mvvm大话开篇

MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负 责显示.作为一种新的模式,MVP与MVC有着一个重大的区别:在MVP中View并不直接使用Model,它们之间的通信是通过Presenter (MVC中的Controller)来进行的,所有的交互都发生在Presenter内部,而在MVC中View会从直接Model中读取数据而不是通过 Controller. 在MVC里,View是可以直接访问

常见架构风格

软件架构决策派定义中列举了一系列架构设计阶段需要完成的决策,其中包括“确定架构风格”,那么什么是架构风格?都有哪些常见的架构风格呢? 定义 架构风格定义了一组可以使用的元素类型(比如模块.组件.连接器等),还定义了一组如何使用这些类型的约束,比如系统的实时拓扑结构.模块之间的依赖及组件之间的可视性等. 其实架构风格就和设计模式类似,都是定义了组件及组件之间的关系,不过抽象层次不同而已,因此他们的作用也很类似. 作用 一致性和可理解性:遵循同一个风格得到的结果是一个好主意被彻底的贯彻实施了,而不是

[android架构篇]mvp+rxjava+retrofit+eventBus

android架构篇 mvp+rxjava+retrofit+eventBus 高层不应该知道低层的细节,应该是面向抽象的编程.业务的实现交给实现的接口的类.高层只负责调用. 首先,要介绍一下一个项目中好架构的好处:好的软件设计必须能够帮助开发者发展和扩充解决方案,保持代码清晰健壮,并且可扩展,易于维护,而不必每件事都重写代码.面对软件存在的问题,必须遵守SOLID原则(面向对象五大原则),不要过度工程化,尽可能降低框架中模块的依赖性. 之前的一段时间,学习了一些新的技术,并把自己关注的技术整合

安卓入门常见架构之mvc

Android基础--框架模式MVC在安卓中的实践 本篇文章包含以下内容: MVC的介绍 MVC的实践 MVC的介绍 MVC (Model View Controller),是模型(model)视图(view)控制器(controller)的缩写,一种软件设计模式,用于组织代码用一种功能模块和数据模块分离的方法 Model:模型层,负责处理数据的加载或者存储 View:视图层,负责界面数据的展示,与用户进行交互 Controller:控制器层,负责逻辑业务的处理 MVC的模型关系图: MVC设计

安卓实践开发之MVP一步步实现到高级封装

在上家干了快2年辞职后在家休息了快一个月了,说实在的不上班的感觉爽(睡觉睡到自然醒,游戏玩到手抽筋).哈哈,又是快到一年过中秋的时候了,好久没有更新博客了,今天顺便撸一篇. 前言 话说MVP的模式已经问世好几年了,为什么很多公司还是不愿意接受呢?说实在的我就还是喜欢自己的mvc,不喜欢看见mvp庞大的架构,所以前公司的项目呢也不曾使用过mvp(同事也不接受这种模式),毕竟项目架构不是特别复杂的话使用mvp显示不出他的优势,相反给人的感觉是实现一个界面多出了很多的代码. 然而现在最火的应该是mvv

安卓开发 第七篇 我的安卓应用架构设计-----Adapter类及ViewHolder类

在Android开发中,对于AdapterView类型的控件,我们都需要通过适配器来给它设置数据,如果显示的内容比较简单,我们通常使用SimpleAdapter或者ArrayAdapter,而对于复杂多变的数据,我们一般使用自定义一个继承自BaseAdapter的Adapter来处理.为了itemview的复用,我们通常用一个Viewholder来包装itemview里面的控件. 在我的安卓架构中,使用BaseAbsListAdapter作为所有AbsListView的适配器的基类: /** *

MySQL常见架构的应用

MySQL 的架构设计 MySQL 架构一定要结合前台业务来设计.优化,所以不管是哪种架构.根据业务要求组合成符合需求的即是最好的.不能泛泛而谈同时.也必须注意数据的安全(如ipsec,ssh,vpn传输) MySQL常见的架构 MySQL常见的架构都是进行业务切分.前端缓存.分库分表.若是过亿的查询量则先从业务上拆分.将 bbs.web.blog 分成几个组.然后再做成一主多从.读写分离的方式而且.在设计表的时候.一般情况下.备库常充当起备份查询的作用,至于.读写分离.在程序设计之初.读和写是