原文地址点这里

MVP大家最先想到的应该是LOL和CF里面的MVP荣誉吧,玩过的应该都知道指的是Most-Valuable-Player(全场表现最佳DE游戏玩家)

以前也经常玩,平常凌晨一两点,周末凌晨三四点,想想那段时间还是挺疯的,浪费了那么多时间,现在得赶紧抓紧时间好好学习,多写简书,好好工作,定个小目标,挣他一个亿!

好了废话就不多说,进入正题,我们这里说的MVP则是一种设计模式,说起MVP那就要先说说MVC设计模式了,MVP就是由MVC演变而来的。

MVC由Model、View、Control组成。
Model数据模型,提供数据
View视图模型,提供视图展示
Control控制器,负责控制Model和View通信

MVC在Android中的应用,如下图,Activity为Control,XML为View,请求网络数据模块为Model。View箭头指向Control意为传递数据,那就是Control获取View的数据传递给Model来请求网络,请求到的数据直接传递给View来显示,这是一条主线。还有一条就是底部这两个箭头,也就是说Model可以不通过Control,直接获取View的数据,然后再返回结果数据给View。

MVC.png

MVP由Model、View、Presenter组成。
Model数据模型,提供数据
View视图模型,提供视图展示
Presenter主持者,负责逻辑处理

MVP与MVC最明显的区别就在于Presenter和Control了。如下图,Presenter传递数据给Model,Model得到数据来请求网络,再返回数据给Presenter,Presenter再把得到的Model数据传递给View显示。MVP整体的一个流程就是这样。相比MVC来说,Model和View互相不干涉,达到完全解耦

MVP.png

估计上面文字性的解释都听得有点晕,那我们就拿个例子来实战一下吧

下面和大家一起完成一个简单查询快递信息的例子,里面用到了当下最流行的架构RxJava+Retrofit+MVP+OkHttp,非常值得大家一学

配置环境

在builde.gradle里面添加

compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.okhttp3:okhttp:3.4.1'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'io.reactivex:rxjava:1.1.6'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'

在AndroidManifest.xml添加所需权限

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

初始化配置Retrofit

public class MainApp extends Application {@Overridepublic void onCreate() {super.onCreate();//初始化retrofitUtilsRetrofitUtils.getInstance().initOkHttp(this);}
}

在MainApp中初始化Retrofit,设置超时和baseUrl,添加了日志拦截以及RxJava和数据解析,并暴露一个getRetrofit()方法供需要的地方调用

public class RetrofitUtils {private Retrofit retrofit;private String baseUrl = "http://www.kuaidi100.com/";private static class SingleLoader{private static final RetrofitUtils INSTANCE = new RetrofitUtils();}public static RetrofitUtils getInstance(){return SingleLoader.INSTANCE;}public void initOkHttp(@NonNull Context context){HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);OkHttpClient client = new OkHttpClient.Builder().connectTimeout(10000L,TimeUnit.MILLISECONDS)       //设置连接超时.readTimeout(10000L,TimeUnit.MILLISECONDS)          //设置读取超时.writeTimeout(10000L, TimeUnit.MILLISECONDS)         //设置写入超时.cache(new Cache(context.getCacheDir(),10 * 1024 * 1024))   //设置缓存目录和10M缓存.addInterceptor(interceptor)    //添加日志拦截器(该方法也可以设置公共参数,头信息).build();retrofit = new Retrofit.Builder().client(client)     //设置OkHttp.baseUrl(baseUrl).addConverterFactory(GsonConverterFactory.create()) //  添加数据解析ConverterFactory.addCallAdapterFactory(RxJavaCallAdapterFactory.create())   //添加RxJava.build();}public Retrofit getRetrofit(){return retrofit;}
}

Model

public interface PostSearchModel {/*** 请求快递信息* @param type 快递类型* @param postid 快递单号* @param callback 结果回调*/void requestPostSearch(String type,String postid,PostSearchCallback callback);interface PostSearchCallback{void requestPostSearchSuccess(PostQueryInfo postQueryInfo);void requestPostSearchFail(String failStr);}
}

创建这个PostSearchModel接口,方便后期可以不修改之前代码灵活切换多种实现方式

public interface PostServiceBiz {@POST("query")Observable<PostQueryInfo> searchRx(@Query("type") String type, @Query("postid") String postid);
}
public class PostQueryInfo {private String message;private String nu;private String ischeck;private String com;private String status;private String condition;private String state;private List<DataBean> data;public static class DataBean {private String time;private String context;private String ftime;}
}

PostQueryInfo没有添加get和set方法,大家自行快捷键了
PostSearchModelImpl实现上面PostSearchModel接口,利用上一篇文章里学的Retrofit结合RxJava来请求网络
这里传了PostSearchCallback回调函数,成功或者失败都通过回调函数返回,完全不需要考虑其它

public class PostSearchModelImpl implements PostSearchModel {@Overridepublic void requestPostSearch(String type, String postid, final PostSearchCallback callback) {RetrofitUtils.getInstance().getRetrofit().create(PostServiceBiz.class).searchRx(type,postid)//访问网络切换异步线程.subscribeOn(Schedulers.io())//响应结果处理切换成主线程.observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<PostQueryInfo>() {@Overridepublic void onCompleted() {//请求结束回调}@Overridepublic void onError(Throwable e) {//错误回调callback.requestPostSearchFail(e.getMessage());}@Overridepublic void onNext(PostQueryInfo postQueryInfo) {//成功结果返回callback.requestPostSearchSuccess(postQueryInfo);}});}
}

View

activity_main.xml主界面布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="16dp"tools:context=".ui.MainActivity"android:orientation="vertical"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="快递公司名:"/><EditTextandroid:id="@+id/post_name_et"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="yuantong"/></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="快 递  单 号:"/><EditTextandroid:id="@+id/post_id_et"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="500379523313"/></LinearLayout><Buttonandroid:id="@+id/post_search_bn"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="查询"/><ListViewandroid:id="@+id/post_list_lv"android:layout_width="match_parent"android:layout_height="match_parent"android:listSelector="@null"android:background="@null"/>
</LinearLayout>

view_item_logistics.xml
listview适配器的item布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="#FFFFFF"android:orientation="vertical"android:padding="15dp"><TextViewandroid:id="@+id/tv_conent"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#8f8f8f"android:textSize="14sp"android:text="【深圳市】广东分公司已出发" /><TextViewandroid:layout_marginTop="13dp"android:id="@+id/tv_date"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textColor="#8f8f8f"android:textSize="12sp"android:layout_marginBottom="13dp"android:paddingLeft="6dp"android:text="2016-05-03 18:23" />
</LinearLayout>

ListView适配器

public class LogisticsAdapter extends BaseAdapter {private List<PostQueryInfo.DataBean> datas;private LayoutInflater inflater;public LogisticsAdapter(Context context, List<PostQueryInfo.DataBean> datas) {this.datas = datas;inflater = LayoutInflater.from(context);}@Overridepublic View getView(int i, View view, ViewGroup viewGroup) {PostQueryInfo.DataBean data = datas.get(i);view = inflater.inflate(R.layout.view_item_logistics, null);TextView tv_content= (TextView) view.findViewById(R.id.tv_conent);TextView tv_date= (TextView) view.findViewById(R.id.tv_date);tv_content.setText(data.getContext().replace("[","【").replace("]","】"));tv_date.setText(data.getTime());return view;}@Overridepublic int getCount() {return datas != null ? datas.size() : 0;}@Overridepublic Object getItem(int i) {return datas.get(i);}@Overridepublic long getItemId(int i) {return i;}
}

BaseView提供通用显示和隐藏加载框,如果有通用的方法都可以在写在这里面

public interface BaseView {void showProgressDialog();    void hideProgressDialog();
}

MainView接口继承提供MainActivity所有需要更新界面UI的方法

public interface MainView extends BaseView{void updateListUI(PostQueryInfo postQueryInfo);void errorToast(String message);
}

BaseActivity实现BaseVew所有接口方法

public class BaseActivity extends Activity implements BaseView{private ProgressDialog progressDialog;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);progressDialog = new ProgressDialog(this);progressDialog.setMessage("查询中...");}@Overridepublic void showProgressDialog(){if(progressDialog!=null){progressDialog.show();}}@Overridepublic void hideProgressDialog(){if(progressDialog!=null&&progressDialog.isShowing()){progressDialog.dismiss(); }}
}

MainActivity继承BaseActivity实现MainView所有方法供PostPresenter调用,点击查询按钮通过实例化的PostPresenter,调用相关方法,后面的事情就全部交给PostPresenter去处理了,在activity销毁的时候调用postPresenter.detach()防止内存泄漏

public class MainActivity extends BaseActivity implements View.OnClickListener, MainView {private EditText post_name_et;private EditText post_id_et;private ListView post_list_lv;private Button post_search_bn;private PostPresenter postPresenter;private List<PostQueryInfo.DataBean> dataArray = new ArrayList<>();private LogisticsAdapter logisticsAdapter;@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();initData();initEvent();}private void initView() {post_name_et = (EditText) findViewById(R.id.post_name_et);post_id_et = (EditText) findViewById(R.id.post_id_et);post_list_lv = (ListView) findViewById(R.id.post_list_lv);post_search_bn = (Button) findViewById(R.id.post_search_bn);}private void initData() {logisticsAdapter = new LogisticsAdapter(getApplicationContext(),dataArray);postPresenter = new PostPresenter(this);post_list_lv.setAdapter(logisticsAdapter);}private void initEvent() {post_search_bn.setOnClickListener(this);}@Overridepublic void onClick(View v) {switch(v.getId()){case R.id.post_search_bn:postPresenter.requestHomeData(post_name_et.getText().toString(),post_id_et.getText().toString());break;}}@Overridepublic void updateListUI(PostQueryInfo postQueryInfo) {dataArray.clear();dataArray.addAll(postQueryInfo.getData());logisticsAdapter.notifyDataSetChanged();}@Overridepublic void errorToast(String message) {Toast.makeText(getApplicationContext(),message,Toast.LENGTH_LONG).show();}@Overrideprotected void onDestroy(){//防止activity销毁,postPresenter对象还存在造成的内存泄漏if(postPresenter!=null) postPresenter.detach();super.onDestroy();}
}

Presenter

BasePresenter基类,提供了一个通用view对象,以及初始化和销毁view对象的方法

public abstract class BasePresenter<T>{public T mView;public void attach(T view){this.mView = view;}public void detach(){mView = null;}
}

PostPresenter在构造函数中通过基类attach的方法初始化MainActivity提供的view对象,实例化PostSearchModelImpl对象,通过它提供的方法来请求网络数据,在成功和失败回调的函数里,可以做一些逻辑处理,通过view对象更新相应的UI

public class PostPresenter extends BasePresenter<MainView>{private PostSearchModel postSearchModel;public PostPresenter(MainView mainView){attach(mainView);postSearchModel = new PostSearchModelImpl();}public void requestHomeData(String type,String postid){if(postSearchModel == null||mView == null)return;mView.showProgressDialog();postSearchModel.requestPostSearch(type, postid, new PostSearchModel.PostSearchCallback() {@Overridepublic void requestPostSearchSuccess(PostQueryInfo postQueryInfo) {mView.hideProgressDialog();if(postQueryInfo!=null&&"ok".equals(postQueryInfo.getMessage())) {mView.updateListUI(postQueryInfo);}}@Overridepublic void requestPostSearchFail(String failStr) {mView.hideProgressDialog();mView.errorToast(failStr);}});}
}

到这里全部代码基本都已编写完,代码的结构如下图:

MVP结构图.png

下面就运行程序看看效果吧,快递公司名和快递单号默认填写上去了,大家只需要点击查询,结果和下面图片一样就说明成功了

快递查询.png

为什么没有直接提供一个可以运行的DEMO出来,原因很简单就是希望大家能够跟着一步一步学习,然后动手慢慢边敲代码边理解,最后敲完运行成功,应该就会更加理解MVP了。

个人感悟:在没有学习mpv之前我总觉得这种东西就是多此一举,只要你的逻辑能力可以,代码封装足够清晰,完全可以将臃肿的activity解放出来,mvc又怎样,一样的好用,并且成本特别低你不需要去写各种接口去分离业务模型和ui,并且相对代码也少了很多。但是这样对于一个团队来说,就有点难度了,因为你不能强制你的队友去做各种封装和分离,有时往往是你刚将业务逻辑分离封装完成,搞了一个简洁的activity。回过头来你的队友就有可能直接在activity中写了一堆逻辑操作,有时候干脆连方法都懒得写,直接在现有方法里写了,回过头来看到是不是有种想打人的感觉。所以说使用mvc也能将代码写的先对有条理,逻辑清晰,是比较难的。

回过头来我们再来看下mvp,它其实就像一个架子,只要我们把这个架子搭好,代码就不会太乱,就拿上边我们学习的代码的分包来说。

adapter:主要就是各种的适配器

base:是各种子类公共业务的集合,可以是抽象类也可以是接口

bean:是我们常用的数据模型,通过与第三方结合直接获取到数据

mode:这个就是mvp 中得m  主要用于获取数据源包括数据库,网络等。

postService:用于定义我们使用的网络接口

ui:是activity ,自定义view ,及fragment

view:就是更新ui所需的接口

presenter:这个就是mvp 中得p 也是view 和mode 沟通的桥梁。他主要就是通过ui的到的参数然后调用mode 获取数据,得到数据据结果后通过view 来更新ui

utils :公共的工具类,可以是模块内的公共类也可以是模块外所有模块的公共类

基本这就是一个模块完整的分包了,下面是具体的一个操作流程图,

Android 你应该学会的设计模式MVP相关推荐

  1. android开发模式,Android开发中无处不在的设计模式

    Android开发中无处不在的设计模式――单例模式 Android开发中无处不在的设计模式――Builder模式 前面介绍了单例模式和Builder模式,有兴趣的见上面两个链接,这篇文章侧重介绍1下视 ...

  2. Android开发中无处不在的设计模式——动态代理模式

    继续更新设计模式系列.写这个模式的主要原因是近期看到了动态代理的代码. 先来回想一下前5个模式: - Android开发中无处不在的设计模式--单例模式 - Android开发中无处不在的设计模式-- ...

  3. android的手势解锁功能,Android应用开发之Android 5秒学会使用手势解锁功能

    本文将带你了解Android应用开发Android 5秒学会使用手势解锁功能,希望本文对大家学Android有所帮助. Android手势解锁 本文讲述的是一个手势解锁的库,可以定制显示隐藏宫格点.路 ...

  4. android解锁动画效果,Android 5秒学会使用手势解锁功能

    Android手势解锁 本文讲述的是一个手势解锁的库,可以定制显示隐藏宫格点.路径.并且带有小九宫格显示图,和震动!让你学会使用这个简单,高效的库! 先来一波效果效果展示: 手势解锁效果 今天给大家介 ...

  5. cocos2d android开发,Cocos2d android(一个钟点学会FlyppyBird开发)

    Cocos2d android(一个小时学会FlyppyBird开发) 首先请下载源码程序....... (下面内容请再熟悉Android开发以后继续观看) ~~~~~~~~~~~~~~~~~~~~~ ...

  6. Android开发中常见的设计模式

    对于开发人员来说,设计模式有时候就是一道坎,但是设计模式又非常有用,过了这道坎,它可以让你水平提高一个档次.而在android开发中,必要的了解一些设计模式又是非常有必要的.对于想系统的学习设计模式的 ...

  7. Android 系统(77)---MVC,MVP,MVVM的区别

    MVC,MVP,MVVM的区别 一.MVC 软件可以分为三部分 1.Model:模型层,负责处理数据的加载或者存储  2. View:视图层,负责界面数据的展示,与用户进行交互  3.Controll ...

  8. android 通知写法_Android架构设计MVP模式第(二)篇,如何减少类爆炸

    code小生 一个专注大前端领域的技术平台公众号回复Android加入安卓技术群 作者:LooperJing 链接:https://www.jianshu.com/p/3a17382d44de 声明: ...

  9. android设计架构之MVC、MVP、MVVM的理解

    引用网上的一张图来阐述Model-View-Controller,Model-View-Presenter,Model-View-ViewModel; Model-View-Controller:是我 ...

最新文章

  1. Java5的 线程并发库
  2. 负载均衡策略_负载均衡策略
  3. DataWorks OpenAPI企业开发实战-运维监控大屏
  4. CentOS安装ClickHouse
  5. php压缩zip文件类
  6. matlab中的relop,MINP混合整数非线性规划问题求解(MATLAB OPTI toolbox)
  7. rman命令学习-tina(上)
  8. python 3.8.0安卓_Python 3.8.0 正式版发布,新特性初体验
  9. 采用C#泛型实现状态(State)模式
  10. 拓端tecdat|R语言Kaggle泰坦尼克号性别阶级模型数据分析案例
  11. 少儿编程、软硬编程课件、创意Scratch的项目小游戏,可单独上一节课
  12. 浅谈Java的伪随机数发生器和线性同余法
  13. oracle临时表空间最大多大,Oracle临时表空间过大解决方法
  14. iReasoning MIB Browser显示中文乱码问题
  15. 分布式系统中Topology(Rack) Awareness的实现思路
  16. 【DirectX11】【学习笔记(10)】混合
  17. SitePoint Smackdown:Atom,括号,Light Table,Sublime Text
  18. (Paper)Network in Network网络分析
  19. 日语身体各部位怎么说 最全的
  20. Unity实现刀光特效

热门文章

  1. paper3:UV-GAN: Adversarial Facial UV Map Completion for Pose-invariant Face Recognition
  2. Activity 跳转详解
  3. 数据多维分析 - 派可数据商业智能BI可视化分析平台
  4. python小学生课本剧_小学生都能学会的python(生成器)
  5. cocos2d x游戏开发系列教程 中国象棋01 工程文件概述
  6. Java ——MongDB 插入数据、 模糊查询、in查询
  7. 利用OpenCV的霍夫变换线检测函数HoughLines()得到直线的ρ和θ值后绘制直线的原理详解
  8. hadoop mapreduce相关类 FileInputFormat
  9. 创建德鲁伊数据库连接池实例
  10. 老鸟的Python入门教程