Android MVP架构从入门到精通-真枪实弹

  • 一. 前言
  • 二. MVC架构
    • 1. MVC架构优缺点
      • A. 缺点
      • B. 优点
  • 三. MVP架构
    • 1. MVP架构优缺点
      • A. 缺点
      • B. 优点
  • 四. MVP架构实战(真枪实弹)
    • 1. MVP三层代码简单书写
    • 2. P层V层沟通桥梁
    • 3. 生命周期适配
    • 4. 优化MVP架构
    • 5. 单页面多网络请求以及P层复用
    • 6. 完整项目地址
  • 五. 参考资料
  • 六. 后续

一. 前言

你是否遇到过Activity/Fragment中成百上千行代码,完全无法维护,看着头疼?

你是否遇到过因后台接口还未写而你不能先写代码逻辑的情况?

你是否遇到过用MVC架构写的项目进行单元测试时的深深无奈?

如果你现在还是用MVC架构模式在写项目,请先转到MVP模式!

二. MVC架构

MVC架构模式最初生根于服务器端的Web开发,后来渐渐能够胜任客户端Web开发,再后来因Android项目由XML和Activity/Fragment组成,慢慢的Android开发者开始使用类似MVC的架构模式开发应用.

M层:模型层(model),主要是实体类,数据库,网络等存在的层面,model将新的数据发送到view层,用户得到数据响应.

V层:视图层(view),一般指XML为代表的视图界面.显示来源于model层的数据.用户的点击操作等事件从view层传递到controller层.

C层:控制层(controller),一般以Activity/Fragment为代表.C层主要是连接V层和M层的,C层收到V层发送过来的事件请求,从M层获取数据,展示给V层.

从上图可以看出M层和V层有连接关系,而Activity有时候既充当了控制层又充当了视图层,导致项目维护比较麻烦.

1. MVC架构优缺点
A. 缺点
  1. M层和V层有连接关系,没有解耦,导致维护困难.

  2. Activity/Fragment中的代码过多,难以维护.

Activity中有很多关于视图UI的显示代码,因此View视图和Activity控制器并不是完全分离的,当Activity类业务过多的时候,会变得难以管理和维护.尤其是当UI的状态数据,跟持久化的数据混杂在一起,变得极为混乱.

B. 优点
  1. 控制层和View层都在Activity中进行操作,数据操作方便.

  2. 模块职责划分明确.主要划分层M,V,C三个模块.

三. MVP架构

MVP,即是Model,View,Presenter架构模式.看起来类似MVC,其实不然.从上图能看到Model层和View层没有相连接,完全解耦.

用户触碰界面触发事件,View层把事件通知Presenter层,Presenter层通知Model层处理这个事件,Model层处理后把结果发送到Presenter层,Presenter层再通知View层,最后View层做出改变.这是一整套流程.

M层:模型层(Model),此层和MVC中的M层作用类似.

V层:视图层(View),在MVC中V层只包含XML文件,而MVP中V层包含XML,Activity和Fragment三者.理论上V层不涉及任何逻辑,只负责界面的改变,尽量把逻辑处理放到M层.

P层:通知层(Presenter),P层的主要作用就是连接V层和M层,起到一个通知传递数据的作用.

1. MVP架构优缺点
A. 缺点
  1. MVP中接口过多.

  2. 每一个功能,相比于MVC要多写好几个文件.

  3. 如果某一个界面中需要请求多个服务器接口,这个界面文件中会实现很多的回调接口,导致代码繁杂.

  4. 如果更改了数据源和请求中参数,会导致更多的代码修改.

  5. 额外的代码复杂度及学习成本.

B. 优点
  1. 模块职责划分明显,层次清晰,接口功能清晰.

  2. Model层和View层分离,解耦.修改View而不影响Model.

  3. 功能复用度高,方便.一个Presenter可以复用于多个View,而不用更改Presenter的逻辑.

  4. 有利于测试驱动开发,以前的Android开发是难以进行单元测试.

  5. 如果后台接口还未写好,但已知返回数据类型的情况下,完全可以写出此接口完整的功能.

四. MVP架构实战(真枪实弹)

1. MVP三层代码简单书写

接下来笔者从简到繁,一点一点的堆砌MVP的整个架构.先看一下XML布局,布局中一个Button按钮和一个TextView控件,用户点击按钮后,Presenter层通知Model层请求处理网络数据,处理后Model层把结果数据发送给Presenter层,Presenter层再通知View层,然后View层改变TextView显示的内容.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns: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:layout_gravity="center"android:gravity="center"android:orientation="vertical"tools:context=".view.SingleInterfaceActivity"><Buttonandroid:id="@+id/button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="点击" /><TextViewandroid:id="@+id/textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="100px"android:text="请点击上方按钮获取数据" />
</LinearLayout>

接下来是Activity代码,里面就是获取Button和TextView控件,然后对Button做监听,先简单的这样写,一会慢慢的增加代码.

public class SingleInterfaceActivity extends AppCompatActivity {private Button button;private TextView textView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_single_interface);button = findViewById(R.id.button);textView = findViewById(R.id.textView);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});}
}

下面是Model层代码.本次网络请求用的是wanandroid网站的开放api,其中的文章首页列表接口.SingleInterfaceModel文件里面有一个方法getData,第一个参数curPage意思是获取第几页的数据,第二个参数callback是Model层通知Presenter层的回调.

public class SingleInterfaceModel {public void getData(int curPage, final Callback callback) {NetUtils.getRetrofit().create(Api.class).getData(curPage).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<ArticleListBean>() {@Overridepublic void onCompleted() {LP.w("completed");}@Overridepublic void onError(Throwable e) {callback.onFail("出现错误");}@Overridepublic void onNext(ArticleListBean bean) {if (null == bean) {callback.onFail("出现错误");} else if (bean.errorCode != 0) {callback.onFail(bean.errorMsg);} else {callback.onSuccess(bean);}}});}
}

Callback文件内容如下.里面一个成功一个失败的回调接口,参数全是泛型,为啥使用泛型笔者就不用说了吧.

public interface Callback<K, V> {void onSuccess(K data);void onFail(V data);
}

再接下来是Presenter层的代码.SingleInterfacePresenter类构造函数中直接new了一个Model层对象,用于Presenter层对Model层的调用.然后SingleInterfacePresenter类的方法getData用于与Model的互相连接.

public class SingleInterfacePresenter {private final SingleInterfaceModel singleInterfaceModel;public SingleInterfacePresenter() {this.singleInterfaceModel = new SingleInterfaceModel();}public void getData(int curPage) {singleInterfaceModel.getData(curPage, new Callback<ArticleListBean, String>() {@Overridepublic void onSuccess(ArticleListBean loginResultBean) {//如果Model层请求数据成功,则此处应执行通知View层的代码}@Overridepublic void onFail(String errorMsg) {//如果Model层请求数据失败,则此处应执行通知View层的代码}});}
}

至此,MVP三层简单的部分代码算是完成.那么怎样进行整个流程的相互调用呢.我们把刚开始的SingleInterfaceActivity代码改一下,让SingleInterfaceActivity持有Presenter层的对象,这样View层就可以调用Presenter层了.修改后代码如下.

public class SingleInterfaceActivity extends AppCompatActivity {private Button button;private TextView textView;private SingleInterfacePresenter singleInterfacePresenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_single_interface);button = findViewById(R.id.button);textView = findViewById(R.id.textView);singleInterfacePresenter = new SingleInterfacePresenter();button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {singleInterfacePresenter.getData(0);}});}
}

从以上所有代码可以看出,当用户点击按钮后,View层按钮的监听事件执行调用了Presenter层对象的getData方法,此时,Presenter层对象的getData方法调用了Model层对象的getData方法,Model层对象的getData方法中执行了网络请求和逻辑处理,把成功或失败的结果通过Callback接口回调给了Presenter层,然后Presenter层再通知View层改变界面.但此时SingleInterfacePresenter类中收到Model层的结果后无法通知View层,因为SingleInterfacePresenter未持有View层的对象.如下代码的注释中有说明.(如果此时点击按钮,下方代码LP.w()处会打印出网络请求成功的log)

public class SingleInterfacePresenter {private final SingleInterfaceModel singleInterfaceModel;public SingleInterfacePresenter() {this.singleInterfaceModel = new SingleInterfaceModel();}public void getData(int curPage) {singleInterfaceModel.getData(curPage, new Callback<ArticleListBean, String>() {@Overridepublic void onSuccess(ArticleListBean loginResultBean) {//如果Model层请求数据成功,则此处应执行通知View层的代码//LP.w()是一个简单的log打印LP.w(loginResultBean.toString());}@Overridepublic void onFail(String errorMsg) {//如果Model层请求数据失败,则此处应执行通知View层的代码}});}
}

代码写到这里,笔者先把这些代码提交到github(https://github.com/serge66/MVPDemo),github上会有一次提交记录,如果想看此时的代码,可以根据提交记录"第一次修改"克隆此时的代码.

2. P层V层沟通桥梁

现在P层未持有V层对象,不能通知V层改变界面,那么就继续演变MVP架构.
在MVP架构中,我们要为每个Activity/Fragment写一个接口,这个接口需要让Presenter层持有,P层通过这个接口去通知V层更改界面.接口中包含了成功和失败的回调,这个接口Activity/Fragment要去实现,最终P层才能通知V层.

public interface SingleInterfaceIView {void showArticleSuccess(ArticleListBean bean);void showArticleFail(String errorMsg);
}

一个完整的项目以后肯定会有许多功能界面,那么我们应该抽出一个IView公共接口,让所有的Activity/Fragment都间接实现它.IVew公共接口是用于给View层的接口继承的,注意,不是View本身继承.因为它定义的是接口的规范, 而其他接口才是定义的类的规范(这句话请仔细理解).

/*** @Description: 公共接口 是用于给View的接口继承的,注意,不是View本身继承。*                    因为它定义的是接口的规范, 而其他接口才是定义的类的规范* @Author: lishengjiejob@163.com* @Time: 2018/11/22 17:26*/
public interface IView {
}

这个接口中可以写一些所有Activigy/Fragment共用的方法,我们把SingleInterfaceIView继承IView接口.

public interface SingleInterfaceIView extends IView {void showArticleSuccess(ArticleListBean bean);void showArticleFail(String errorMsg);
}

同理Model层和Presenter层也是如此.

public interface IModel {
}
public interface IPresenter {
}

现在项目中Model层是一个SingleInterfaceModel类,这个类对象被P层持有,对于面向对象设计来讲,利用接口达到解耦目的已经人尽皆知,那我们就要对SingleInterfaceModel类再写一个可继承的接口.代码如下.

public interface ISingleInterfaceModel extends IModel {void getData(int curPage, final Callback callback);
}

如此,SingleInterfaceModel类的修改如下.

public class SingleInterfaceModel implements ISingleInterfaceModel {@Overridepublic void getData(int curPage, final Callback callback) {NetUtils.getRetrofit().create(Api.class).getData(curPage).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<ArticleListBean>() {@Overridepublic void onCompleted() {LP.w("completed");}@Overridepublic void onError(Throwable e) {callback.onFail("出现错误");}@Overridepublic void onNext(ArticleListBean bean) {if (null == bean) {callback.onFail("出现错误");} else if (bean.errorCode != 0) {callback.onFail(bean.errorMsg);} else {callback.onSuccess(bean);}}});}
}

同理,View层持有P层对象,我们也需要对P层进行改造.但是下面的代码却没有像ISingleInterfaceModel接口继承IModel一样继承IPresenter,这点需要注意,笔者把IPresenter的继承放在了其他处,后面会讲解.

public interface ISingleInterfacePresenter {void getData(int curPage);
}

然后SingleInterfacePresenter类的修改如下:

public class SingleInterfacePresenter implements ISingleInterfacePresenter {private final ISingleInterfaceModel singleInterfaceModel;public SingleInterfacePresenter() {this.singleInterfaceModel = new SingleInterfaceModel();}@Overridepublic void getData(int curPage) {singleInterfaceModel.getData(curPage, new Callback<ArticleListBean, String>() {@Overridepublic void onSuccess(ArticleListBean loginResultBean) {//如果Model层请求数据成功,则此处应执行通知View层的代码//LP.w()是一个简单的log打印LP.w(loginResultBean.toString());}@Overridepublic void onFail(String errorMsg) {//如果Model层请求数据失败,则此处应执行通知View层的代码LP.w(errorMsg);}});}
}
3. 生命周期适配

至此,MVP三层每层的接口都写好了.但是P层连接V层的桥梁还没有搭建好,这个慢慢来,一个好的高楼大厦都是一步一步建造的.上面IPresenter接口我们没有让其他类继承,接下来就讲下这个.P层和V层相连接,V层的生命周期也要适配到P层,P层的每个功能都要适配生命周期,这里可以把生命周期的适配放在IPresenter接口中.P层持有V层对象,这里把它放到泛型中.代码如下.

public interface IPresenter<T extends IView> {/*** 依附生命view** @param view*/void attachView(T view);/*** 分离View*/void detachView();/*** 判断View是否已经销毁** @return*/boolean isViewAttached();}

这个IPresenter接口需要所有的P层实现类继承,对于生命周期这部分功能都是通用的,那么就可以抽出来一个抽象基类BasePresenter,去实现IPresenter的接口.

public abstract class BasePresenter<T extends IView> implements IPresenter<T> {protected T mView;@Overridepublic void attachView(T view) {mView = view;}@Overridepublic void detachView() {mView = null;}@Overridepublic boolean isViewAttached() {return mView != null;}
}

此时,SingleInterfacePresenter类的代码修改如下.泛型中的SingleInterfaceIView可以理解成对应的Activity,P层此时完成了对V层的通信.

public class SingleInterfacePresenter extends BasePresenter<SingleInterfaceIView> implements ISingleInterfacePresenter {private final ISingleInterfaceModel singleInterfaceModel;public SingleInterfacePresenter() {this.singleInterfaceModel = new SingleInterfaceModel();}@Overridepublic void getData(int curPage) {singleInterfaceModel.getData(curPage, new Callback<ArticleListBean, String>() {@Overridepublic void onSuccess(ArticleListBean loginResultBean) {//如果Model层请求数据成功,则此处应执行通知View层的代码//LP.w()是一个简单的log打印LP.w(loginResultBean.toString());if (isViewAttached()) {mView.showArticleSuccess(loginResultBean);}}@Overridepublic void onFail(String errorMsg) {//如果Model层请求数据失败,则此处应执行通知View层的代码LP.w(errorMsg);if (isViewAttached()) {mView.showArticleFail(errorMsg);}}});}
}

此时,P层和V层的连接桥梁已经搭建,但还未搭建完成,我们需要写个BaseMVPActvity让所有的Activity继承,统一处理Activity相同逻辑.在BaseMVPActvity中使用IPresenter的泛型,因为每个Activity中需要持有P层对象,这里把P层对象抽出来也放在BaseMVPActvity中.同时BaseMVPActvity中也需要继承IView,用于P层对V层的生命周期中.代码如下.

public abstract class BaseMVPActivity<T extends IPresenter> extends AppCompatActivity implements IView {protected T mPresenter;@Overrideprotected void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);initPresenter();init();}protected void initPresenter() {mPresenter = createPresenter();//绑定生命周期if (mPresenter != null) {mPresenter.attachView(this);}}@Overrideprotected void onDestroy() {if (mPresenter != null) {mPresenter.detachView();}super.onDestroy();}/*** 创建一个Presenter** @return*/protected abstract T createPresenter();protected abstract void init();}

接下来让SingleInterfaceActivity实现这个BaseMVPActivity.

public class SingleInterfaceActivity extends BaseMVPActivity<SingleInterfacePresenter> implements SingleInterfaceIView {private Button button;private TextView textView;@Overrideprotected void init() {setContentView(R.layout.activity_single_interface);button = findViewById(R.id.button);textView = findViewById(R.id.textView);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mPresenter.getData(0);}});}@Overrideprotected SingleInterfacePresenter createPresenter() {return new SingleInterfacePresenter();}@Overridepublic void showArticleSuccess(ArticleListBean bean) {textView.setText(bean.data.datas.get(0).title);}@Overridepublic void showArticleFail(String errorMsg) {Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show();}
}

到此,MVP架构的整个简易流程完成.

代码写到这里,笔者先把这些代码提交到github(https://github.com/serge66/MVPDemo),github上会有一次提交记录,如果想看此时的代码,可以根据提交记录"第二次修改"克隆此时的代码.

4. 优化MVP架构

上面是MVP的目录,从目录中我们可以看到一个功能点(网络请求)MVP三层各有两个文件需要写,相对于MVC来说写起来确实麻烦,这也是一些人不愿意写MVP,宁愿用MVC的原因.

这里我们可以对此优化一下.MVP架构中有个Contract的概念,Contract有统一管理接口的作用,目的是为了统一管理一个页面的View和Presenter接口,用Contract可以减少部分文件的创建,比如P层和V层的接口文件.

那我们就把P层的ISingleInterfacePresenter接口和V层的SingleInterfaceIView接口文件删除掉,放入SingleInterfaceContract文件中.代码如下.

public interface SingleInterfaceContract {interface View extends IView {void showArticleSuccess(ArticleListBean bean);void showArticleFail(String errorMsg);}interface Presenter {void getData(int curPage);}}

此时,SingleInterfacePresenter和SingleInterfaceActivity的代码修改如下.

public class SingleInterfacePresenter extends BasePresenter<SingleInterfaceContract.View>implements SingleInterfaceContract.Presenter {private final ISingleInterfaceModel singleInterfaceModel;public SingleInterfacePresenter() {this.singleInterfaceModel = new SingleInterfaceModel();}@Overridepublic void getData(int curPage) {singleInterfaceModel.getData(curPage, new Callback<ArticleListBean, String>() {@Overridepublic void onSuccess(ArticleListBean loginResultBean) {//如果Model层请求数据成功,则此处应执行通知View层的代码//LP.w()是一个简单的log打印LP.w(loginResultBean.toString());if (isViewAttached()) {mView.showArticleSuccess(loginResultBean);}}@Overridepublic void onFail(String errorMsg) {//如果Model层请求数据失败,则此处应执行通知View层的代码LP.w(errorMsg);if (isViewAttached()) {mView.showArticleFail(errorMsg);}}});}
}
public class SingleInterfaceActivity extends BaseMVPActivity<SingleInterfacePresenter>implements SingleInterfaceContract.View {private Button button;private TextView textView;@Overrideprotected void init() {setContentView(R.layout.activity_single_interface);button = findViewById(R.id.button);textView = findViewById(R.id.textView);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mPresenter.getData(0);}});}@Overrideprotected SingleInterfacePresenter createPresenter() {return new SingleInterfacePresenter();}@Overridepublic void showArticleSuccess(ArticleListBean bean) {textView.setText(bean.data.datas.get(0).title);}@Overridepublic void showArticleFail(String errorMsg) {Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show();}
}

代码写到这里,笔者先把这些代码提交到github(https://github.com/serge66/MVPDemo),github上会有一次提交记录,如果想看此时的代码,可以根据提交记录"第三次修改"克隆此时的代码.

5. 单页面多网络请求以及P层复用

上面的MVP封装只适用于单页面一个网络请求的情况,当一个界面有两个网络请求时,此封装已不适合.以及考虑到P层复用.为此,我们再次新建一个MultipleInterfaceActivity来进行说明.XML中布局是两个按钮两个Textview,点击则可以进行网络请求.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns: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:layout_gravity="center"android:gravity="center"android:orientation="vertical"tools:context=".view.MultipleInterfaceActivity"><Buttonandroid:id="@+id/button"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="点击" /><TextViewandroid:id="@+id/textView"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="50px"android:text="请点击上方按钮获取数据" /><Buttonandroid:id="@+id/btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="100px"android:text="点击" /><TextViewandroid:id="@+id/tv"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginTop="50px"android:text="请点击上方按钮获取数据" />
</LinearLayout>

MultipleInterfaceActivity类代码暂时如下.

public class MultipleInterfaceActivity extends BaseMVPActivity {private Button button;private TextView textView;private Button btn;private TextView tv;@Overrideprotected void init() {setContentView(R.layout.activity_multiple_interface);button = findViewById(R.id.button);textView = findViewById(R.id.textView);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});btn = findViewById(R.id.btn);tv = findViewById(R.id.tv);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});}@Overrideprotected IPresenter createPresenter() {return null;}}

此时我们可以想下,当一个页面中有多个网络请求时,Activity所继承的BaseMVPActivity的泛型中要写多个参数,那有没有上面代码的框架不变的情况下实现这个需求呢?答案必须有的.我们可以把多个网络请求的功能当做一个网络请求来看待,封装成一个MultiplePresenter,其继承至BasePresenter实现生命周期的适配.此MultiplePresenter类的作用就是容纳多个Presenter,连接同一个View.代码如下.

public class MultiplePresenter<T extends IView> extends BasePresenter<T> {private T mView;private List<IPresenter> presenters = new ArrayList<>();@SafeVarargspublic final <K extends IPresenter<T>> void addPresenter(K... addPresenter) {for (K ap : addPresenter) {ap.attachView(mView);presenters.add(ap);}}public MultiplePresenter(T mView) {this.mView = mView;}@Overridepublic void detachView() {for (IPresenter presenter : presenters) {presenter.detachView();}}}

因MultiplePresenter类中需要有多个网络请求,现在举例说明时,暂时用两个网络请求接口.MultipleInterfaceActivity类中代码改造如下.

public class MultipleInterfaceActivity extends BaseMVPActivity<MultiplePresenter>implements SingleInterfaceContract.View, MultipleInterfaceContract.View {private Button button;private TextView textView;private Button btn;private TextView tv;private SingleInterfacePresenter singleInterfacePresenter;private MultipleInterfacePresenter multipleInterfacePresenter;@Overrideprotected void init() {setContentView(R.layout.activity_multiple_interface);button = findViewById(R.id.button);textView = findViewById(R.id.textView);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {singleInterfacePresenter.getData(0);}});btn = findViewById(R.id.btn);tv = findViewById(R.id.tv);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {multipleInterfacePresenter.getBanner();}});}@Overrideprotected MultiplePresenter createPresenter() {MultiplePresenter multiplePresenter = new MultiplePresenter(this);singleInterfacePresenter = new SingleInterfacePresenter();multipleInterfacePresenter = new MultipleInterfacePresenter();multiplePresenter.addPresenter(singleInterfacePresenter);multiplePresenter.addPresenter(multipleInterfacePresenter);return multiplePresenter;}@Overridepublic void showArticleSuccess(ArticleListBean bean) {textView.setText(bean.data.datas.get(0).title);}@Overridepublic void showArticleFail(String errorMsg) {Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show();}@Overridepublic void showMultipleSuccess(BannerBean bean) {tv.setText(bean.data.get(0).title);}@Overridepublic void showMultipleFail(String errorMsg) {Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show();}
}

写到这里,MVP框架基本算是完成.如果想再次优化,其实还是有可优化的地方,比如当View销毁时,现在只是让P层中的View对象置为null,并没有继续对M层通知.如果View销毁时,M层还在请求网络中呢,可以为此再加入一个取消网络请求的通用功能.这里只是举一个例子,每个人对MVP的理解不一样,而MVP架构也并不是一成不变,适合自己项目的才是最好的.

6. 完整项目地址

完整项目已提交到github(https://github.com/serge66/MVPDemo),若需要敬请查看.

五. 参考资料

一步步带你精通MVP
从0到1搭建MVP框架
Presenter层如何高度的复用

六. 后续

<<MVVM架构从入门到精通-真枪实弹>> 敬请期待~~~

原创文章,来自于Vitamio(http://blog.csdn.net/vitamio),转载请注明出处。

Android MVP架构从入门到精通-真枪实弹相关推荐

  1. mvp关联activity生命周期_Android MVP架构从入门到精通-真枪实弹

    Android MVP架构从入门到精通-真枪实弹 一. 前言 你是否遇到过Activity/Fragment中成百上千行代码,完全无法维护,看着头疼? 你是否遇到过因后台接口还未写而你不能先写代码逻辑 ...

  2. [Android] Android MVP 架构下 最简单的 代码实现

    Android  MVP 架构下  最简单的 代码实现 首先看图: 上图是MVP,下图是MVC MVP和MVC的区别,在于以前的View层不仅要和model层交互,还要和controller层交互.而 ...

  3. java架构师入门教程,java技术架构师入门到精通高薪就业教程百度云下载

    java技术架构师入门到精通高薪就业视频教程百度云 课程目录: JAVA架构课开班典礼 JVM性能调优专题 JVM整体结构深度解析 JVM内存分配机制详解(此视频作废) JVM字节码文件结构深度剖析 ...

  4. 微服务架构从入门到精通(一)微服务介绍

    本系列文章包括微服务介绍.微服务架构.DevOps.APM等方面,尽量抓重点.不罗嗦,讲解微服务整个生态圈的技术性知识.期望各位同仁能快速的对微服务架构有个了解,加入到微服务最佳实践中来. 一.架构的 ...

  5. 微服务架构从入门到精通(二)微服务生态体系

    本篇承接上一篇文章<微服务架构从入门到精通(一)微服务介绍>讲起,主要是介绍微服务架构的技术生态体系,让大家对微服务架构整个生态圈有个大体的了解.10来多年的从业经验来看,学习技术一般都是 ...

  6. Android基础教程——从入门到精通(上)

    本文是对B站教程 动脑学院 Android教程 学习过程中所做的笔记. 文章分为上下两部分,此文是上部分,下部分链接为:Android基础教程--从入门到精通(下) 源视频教程并没有录制全,本文还补充 ...

  7. Android MVP架构

    Android 架构的理解昨天看了Android框架模式(1)-MVP入门,感觉理解起来有点困难,我就重新把java回调重新理解了一遍,并写了一篇博客,有需要的朋友可以看一看,java回调机制,下面我 ...

  8. 谈谈 Android MVP 架构 | 掘金技术征文

    前言:本文所写的是博主的个人见解,如有错误或者不恰当之处,欢迎私信博主,加以改正!原文链接,demo链接 MVP 架构简介 说起 MVP 架构,相信很多朋友都看过,网上也有很多这方面的资料.博主使用 ...

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

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

最新文章

  1. 图像的矩,以及利用矩求图像的重心,方向
  2. matlab中怎么给符号变量赋值
  3. 静态call 动态call LINK
  4. BluePrism初尝2
  5. echart旭日图_海报级设计感的旭日图,就在 ECharts 4.0
  6. 用单片机测量流体流速的_沟渠流量测量系统宝山哪家质量好广州顺仪品牌
  7. sql 联合_SQL联合,SQL联合全部
  8. 主要由javascript实现的网页打字小游戏
  9. 解决三星PM981硬盘无法正常安装黑苹果的问题(第一版)
  10. eclipse插件下载地址
  11. 武汉知名 IT 公司大盘点
  12. 使用scrapy爬取前程无忧51job网站
  13. SupeSite模板中的代码代表什么意思
  14. HashMap的底层原理你真的知道?
  15. 13-反向传播法求梯度
  16. css-超出内容省略号
  17. 为何国外的人都爱用电子邮箱?注册电子邮箱有哪些好处呢
  18. Ceph: ceph基础知识
  19. linux系统终端用户名和密码忘记了,主机大师(Linux)登录账户密码忘记的解决办法...
  20. quick-cocos2d-x可调试开发环境搭建(vs+babelua和vscode+luaide)

热门文章

  1. linux通过configfs方式开启uvc、uac、adb等功能
  2. Python推荐系统学习笔记(1)基于协同过滤的个性化推荐算法实战---隐语义模型
  3. 区块链技术将加速人类共享精神的进步
  4. 胡克定律(Hooke's law)
  5. CocoaPods原理
  6. CSS入门保姆级知识整理!!看到就是赚到!(1)
  7. jQuery学习:scroll滚动 垂直滚动scrollTop 水平滚动scrollLeft
  8. linux如何分区ssd和hdd,Linux下判断磁盘是SSD还是HDD的3种方法
  9. MATLAB 最短路
  10. 练习:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少