什么是MVP框架

做Android开发也有好几年时间了,最近接触了Android开发的MVP模式,MVP即Model、View、Presenter的缩写。如果有过一些项目开发经验的人,在项目功能越来越多,逻辑越来越复杂的时候,代码一定会写得越来越乱,乱到自己都很难看下去了(本人在做项目时深有体会)。因为Android以前的开发模式比较类似于MVC框架,XML布局为View层,数据实体为Model层,Activity为Controller层,当一个Activity中的逻辑比较多的时候,Activity中的代码过千行是非常容易达到的,而且很多逻辑和View交互的代码都在Activity中,这样的开发模式,导致View和Controller耦合得非常紧,不仅代码写着看着乱,而且也非常不便于后期的维护和扩展。MVP开发模式的推出,不仅非常有效的解决了View和Controller耦合的问题,而且Activity被彻底当作View来看待了,模型和视图的交互是Presenter和View通过接口来完成,代码层次也分明了,后期的扩展和修改也很方便了。

举个栗子

光说无用,举个例子来说明最实在最容易理解了,下面的一个Demo是我在学习MVP框架时写的,希望自己写得没错(如果有错希望大神指出)
这个项目名为Test MVP,主要功能是实现下载文件,页面上有一个下载按钮,还有一个进度条,下图是项目的目录结构:

下面上布局文件的代码:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/activity_main"android:layout_width="match_parent"android:layout_height="match_parent"android:paddingBottom="@dimen/activity_vertical_margin"android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"tools:context="com.test.testmvp.MainActivity"><Button
        android:id="@+id/download_btn"android:onClick="handleDownloadBtnClick"android:text="CLICK TO DOWNLOAD"android:layout_width="match_parent"android:layout_height="wrap_content" /><ProgressBar
        android:layout_below="@+id/download_btn"android:layout_marginTop="20dp"android:visibility="gone"android:id="@+id/progress_bar"android:max="100"style="@android:style/Widget.ProgressBar.Horizontal"android:layout_width="match_parent"android:layout_height="wrap_content" /></RelativeLayout>

布局文件很简单,就没必要多说明了。
在view包中,主要是一个View的接口文件IDownloadView.java,代码如下:

package com.test.testmvp.view;/*** Created by yubo on 2017/3/26.* view层的抽象接口,需要Activity去实现该接口(所以Activity当作view看待)*/public interface IDownloadView {void initViews();void showProgressBar();void hideProgressBar();void updateProgressBar(int progress);void showToast(String msg);}

这个View的接口文件,定义了一系列有关View的操作的方法,由于MVP模式中将Activity完全视为View来看待,所以我们的Activity需要实现这个IDownloadView接口,关于Activity的具体实现,放在后面贴代码。
下面说presenter包,由于本Demo中主要就是一个下载的逻辑,所以IDownloadPresenter接口中,主要就是一个下载的方法,代码如下:

package com.test.testmvp.presenter;import com.test.testmvp.listener.OnDownloadListener;import java.io.File;/*** Created by yubo on 2017/3/26.*/public interface IDownloadPresenter {//下载文件的逻辑,由实现类去实现该方法,listener用于监听下载过程void startDownload(String urlStr, File saveFile, OnDownloadListener listener);}

下载的IDownloadPresenter接口的startDownload方法有三个参数,第一个是下载地址,第二个是下载的文件,第三个是一个下载的监听器,OnDownloadListener代码如下:

package com.test.testmvp.listener;/*** Created by yubo on 2017/3/26.* 下载的监听器,处理下载的不同阶段*/public interface OnDownloadListener {void onStartDownload();void onProgressUpdate(int progress);void onDownloadSuccess();void onDownloadError(Exception e);}

主要就是监听开始下载、下载进度、下载完成、下载出错这4个过程。有了IDownloadPresenter接口,还需要一个实现类DownloadPresenterImpl,这个实现类的代码如下:

package com.test.testmvp.presenter;import android.app.Activity;
import android.content.Context;import com.test.testmvp.listener.OnDownloadListener;import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;/*** Created by yubo on 2017/3/26.*/public class DownloadPresenterImpl implements IDownloadPresenter {private Context mContext;public DownloadPresenterImpl(Context context) {this.mContext = context;}@Overridepublic void startDownload(final String urlStr, final File saveFile, final OnDownloadListener listener) {if (listener == null) {throw new IllegalArgumentException("OnDownloadListener should not be null!");}listener.onStartDownload();new Thread(new Runnable() {@Overridepublic void run() {InputStream inputStream = null;FileOutputStream fileOutputStream = null;try {URL url = new URL(urlStr);URLConnection conn = url.openConnection();inputStream = conn.getInputStream();fileOutputStream = new FileOutputStream(saveFile);int totalSize = inputStream.available();int hasDownload = 0;int hasRead = 0;byte[] buf = new byte[512];while ((hasRead = inputStream.read(buf)) > 0) {fileOutputStream.write(buf, 0, hasRead);hasDownload += hasRead;final int progress = (int) (hasDownload * 100.0f / totalSize);listener.onProgressUpdate(progress);((Activity)mContext).runOnUiThread(new Runnable() {@Overridepublic void run() {listener.onProgressUpdate(progress);}});}((Activity)mContext).runOnUiThread(new Runnable() {@Overridepublic void run() {listener.onDownloadSuccess();}});} catch (final MalformedURLException e) {e.printStackTrace();((Activity)mContext).runOnUiThread(new Runnable() {@Overridepublic void run() {listener.onDownloadError(e);}});} catch (final IOException e) {e.printStackTrace();((Activity)mContext).runOnUiThread(new Runnable() {@Overridepublic void run() {listener.onDownloadError(e);}});} finally {if (inputStream != null) {try {inputStream.close();} catch (IOException e) {e.printStackTrace();}}if (fileOutputStream != null) {try {fileOutputStream.close();} catch (IOException e) {e.printStackTrace();}}}}}).start();}}

逻辑和视图的解耦,就是靠的Presenter完成的(要是用以前的类似MVC的开发模式,那Presenter中的代码就全部写到Activity中去了)。下面还有一个DownloadFileModel类,就是对下载的文件做了一个简单的封装,代码如下:

package com.test.testmvp.model;import java.io.File;
import java.io.IOException;/*** Created by yubo on 2017/3/26.*/public class DownloadFileModel {private String fileName;private String fileSavePath;private File file;public DownloadFileModel(String fileName, String fileSavePath) {this.fileName = fileName;this.fileSavePath = fileSavePath;this.file = new File(fileSavePath + File.separator + fileName);if (this.file.exists()) {this.file.delete();}try {this.file.createNewFile();} catch (IOException e) {e.printStackTrace();}}public File getFile() {return this.file;}public String getFilePath() {return this.file.getAbsolutePath();}}

下面上MainActivity的代码:

package com.test.testmvp;import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;import com.test.testmvp.listener.OnDownloadListener;
import com.test.testmvp.model.DownloadFileModel;
import com.test.testmvp.presenter.DownloadPresenterImpl;
import com.test.testmvp.view.IDownloadView;public class MainActivity extends AppCompatActivity implements IDownloadView {//文件下载地址,可能已失效private static final String DOWNLOAD_FILE_URL = "http://do.xiazaiba.com/route.php?ct=stat&ac=stat&g=aHR0cDovL2FwcHMud2FuZG91amlhLmNvbS9yZWRpcmVjdD9zaWduYXR1cmU9YzkxNGQ2OSZ1cmw9aHR0cCUzQSUyRiUyRmRvd25sb2FkLmVvZW1hcmtldC5jb20lMkZhcHAlM0ZjaGFubmVsX2lkJTNEMTAwJTI2Y2xpZW50X2lkJTI2aWQlM0QyNDQwMDMmcG49Y29tLnVzb2Z0LmFwcC51aSZtZDU9OTI4MWIxZjU1YmM1YzExNmYyMThmZjYwY2FhZWEwMmImYXBraWQ9MTQyODY1ODgmdmM9MTEmc2l6ZT0zNDE0MTEw";//下载的文件名private static final String DOWNLOAD_FILE_NAME = "test.apk";//下载的文件存放路径private static final String DOWNLOAD_FILE_SAVE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath();//进度条控件private ProgressBar mProgressBar;//处理下载的Presenterprivate DownloadPresenterImpl downloadPresenter;//下载的文件Modelprivate DownloadFileModel downloadFileModel;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initViews();downloadFileModel = new DownloadFileModel(DOWNLOAD_FILE_NAME, DOWNLOAD_FILE_SAVE_PATH);downloadPresenter = new DownloadPresenterImpl(this);}@Overridepublic void initViews() {mProgressBar = (ProgressBar) findViewById(R.id.progress_bar);}//处理下载按钮点击事件public void handleDownloadBtnClick(View view) {downloadPresenter.startDownload(DOWNLOAD_FILE_URL, downloadFileModel.getFile(), new OnDownloadListener() {@Overridepublic void onStartDownload() {showProgressBar();}@Overridepublic void onProgressUpdate(int progress) {updateProgressBar(progress);}@Overridepublic void onDownloadSuccess() {hideProgressBar();showToast("download success, path: " + downloadFileModel.getFilePath());}@Overridepublic void onDownloadError(Exception e) {hideProgressBar();showToast(e.getMessage());}});}@Overridepublic void showProgressBar() {mProgressBar.setVisibility(View.VISIBLE);}@Overridepublic void hideProgressBar() {mProgressBar.setVisibility(View.GONE);}@Overridepublic void updateProgressBar(int progress) {mProgressBar.setProgress(progress);}@Overridepublic void showToast(String msg) {Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();}
}

可以看到Activity实现了IDownloadView接口,并实现了接口里的方法,Activity持有了一个Presenter的引用和一个Model的引用,Activity作为View来看待,当按钮有点击事件时,会调用Presenter的startDownload方法来处理业务逻辑,而视图的更新,是在startDownload方法的回调接口中,调用IDownloadView接口的方法去完成的,不会存在逻辑和视图的直接交互,这样也就达到了低耦合的目的。
OK了,整篇学习笔记就到这里了,希望自己的理解没有错误,也是参考了博客大神的博文来学习的,这里贴出博客大神的文章:
http://blog.csdn.net/lmj623565791/article/details/46596109

本篇学习笔记中的代码已上传到github,点击这里查看代码

Android MVP框架学习相关推荐

  1. Android MVP模式学习

    Android MVP模式学习 参考: Android MVP 开发模式有哪些优缺点?: https://www.zhihu.com/question/35185744 MVP 模式简单易懂的介绍方式 ...

  2. Android MVP框架MVPro的使用和源码分析

    最近看了两篇关于Android实现MVP的文章一种在android中实现MVP模式的新思路和用MVP架构开发Android应用. 两篇文章的思路都是一样的,即把Activity.Fragment作为P ...

  3. android多媒体框架学习 详解

    原址 一:多媒体框架概述 jellybean 的多媒体跟以前的版本,通过对比没啥变化,最大的变化是google终于舍得给multimedia建个独立的git了(framework/av),等你好久了! ...

  4. android多媒体框架学习 详解 最新版本

    一:多媒体框架概述 jellybean 的多媒体跟以前的版本,通过对比没啥变化,最大的变化是google终于舍得给multimedia建个独立的git了(framework/av),等你好久了!也体现 ...

  5. Android MVP框架实现过程

    MVP框架实现过程 目的:View层和Model层分离,中间由Presenter处理逻辑. Prester作为View与Model交互的中间纽带,处理与用户交互的负责逻辑.这里我们只说明View和Pr ...

  6. android MVP框架

    尝试使用MVVM开发模式,让程序解耦. MVVM开发模式图: 优势 模型与视图完全分离,我们可以修改视图而不影响模型: 可以更高效地使用模型,因为所有的交互都发生在一个地方--Presenter内部: ...

  7. Android MVP 框架

    为什么80%的码农都做不了架构师?>>>    前言 根据网络上的MVP套路写了一个辣鸡MVP DEMO 用到的 android studio MVPHelper插件,方便自动生成框 ...

  8. android mvp框架基类,Android MVP架构项目搭建封装,基类封装

    综述 对于MVP (Model View Presenter)架构是从著名的MVC(Model View Controller)架构演变而来的.而对于Android应用的开发中本身可视为一种MVC架构 ...

  9. Android camera2 框架学习记录

    安卓相机架构概览 Android系统利用分层思想,将各层的接口定义与实现分离开来,以接口作为各层的脉络连接整体框架,将具体实现的主导权交由各自有具体实现需求的平台厂商或者Android 开发者,这样既 ...

最新文章

  1. windows10上运行linux,在Windows 10上原生运行Linux
  2. python 节点_python在以太坊开发中节点和网络如何选择?
  3. php pdo mysql哪个好_php pdo和mysqli对比选择
  4. 计算机考研文章精选[转载]
  5. docker web程序本地化_Docker-01-Docker介绍
  6. 敏捷 - #1 原则:早期和持续交付有价值的软件 (#1 Agile Principle)
  7. linux关闭io统计,linux 统计每个进程所占用的io数
  8. 解决 安装或卸载软件时报错Error 1001 的问题
  9. 个人网站如何使用微信扫一扫登录---SpringBoot项目
  10. 使用c语言实现三子棋游戏
  11. 生活记录:突然“醒来”
  12. UE4.26 Niagara Initial Mesh Orientation使用方法
  13. createprocess函数的参数说明:
  14. 浅谈TCP协议的端口(port)
  15. shrio简介--w3cschool
  16. 欢迎广大编程爱好者为MyPage网站提供改进方案
  17. python中ra_consumers-在Python中并行化处理的一种简单、灵活的方法。-Andrew Rabert Documentation Example...
  18. Unity 手机键盘
  19. MacOS 修改MAT内存
  20. 枪火游侠显示无法连接服务器,枪火游侠游戏登录不了怎么解决 枪火游侠为什么进不去游戏...

热门文章

  1. 图片截图识别文字怎么操作?这两个方法不要错过
  2. Druid连接池的基本配置与使用
  3. 3Dmax与Maya哪个更实用
  4. hexo主题应用中遇到的问题和解决方案(持续更新中)
  5. Revit结合Dynamo建立某大桥下部结构-桩基础
  6. RESTful的意义及其使用规则
  7. 虚拟机安装kvm,bios已经开启硬件虚拟化功能,仍显示不支持硬件虚拟化
  8. 安卓逆向——某宝APP抓包之环境对比 (一)
  9. 【Spark实训】-- Spark SQL结构化数据文件处理 ②
  10. 下载 电子商城类型htm模板_【精品素材】 3C数码科技手机产品首页装修psd模板PC端店铺首页设计素材_高清psd图片素材 1920*5054像素...