MVP使用示例

1. 关键点

重要的是要牢记以下几个要点:

  • model中:封装数据存取操作(包括操作数据库或通过网络获取数据)和实体模型;
  • view:指Activity、Fragment或某一具体控件。view中持有presenter的引用;
  • presenter:沟通model和view的桥梁。presenter中持有view和model的引用;
  • 遵循面向接口编程的准则

2. 示例代码

打开一个有列表的Activity,请求数据然后刷新界面。

目录结构

MVP使用示例_第1张图片
目录结构.png

写代码流程

  1. 从View开始写起,当View中需要操作数据时,调用presenter的相关方法。
/**
 * 
 *     author : 杨丽金
 *     time   : 2017/12/27
 *     desc   : 打开一个有列表的Activity界面,请求数据然后刷新界面(MVP写法)
 *     version: 1.0
 * 
*/ public class NewsActivity extends AppCompatActivity implements NewsView { private ListView mLvMvp; private ProgressBar mPbProgress; // View中持有Presenter层的引用 private NewsPresenter presenter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_mvp); initView(); initData(); } private void initData() { initNewsList(); } // 初始化列表 private void initNewsList() { // 请求数据 presenter.requestNewsData(); } private void initView() { mLvMvp = (ListView) findViewById(R.id.mvp_listview); mPbProgress = (ProgressBar) findViewById(R.id.mvp_loading); presenter = new NewsPresenterImpl(this); } }
  1. presenter再调用model中的相关方法;
/**
 * 
 *     author : 杨丽金
 *     time   : 2017/12/27
 *     desc   : presenter是model和view之间的桥梁,它不做具体操作,view划分model才是操作的具体执行者
 *     version: 1.0
 * 
*/ public class NewsPresenterImpl implements NewsPresenter { // presenter中持有View引用 private NewsView newsView; // presenter中持有model引用 private NewsModel newsModel; // 消息处理者 private Handler handler; public NewsPresenterImpl(NewsView newsView) { this.newsView = newsView; // 在构造函数中初始化变量 newsModel = new NewsModelImpl(); // 表示该handler要用主线程的Looper,将消息发送到主线程的MessageQueue中处理消息 handler = new Handler(Looper.getMainLooper()); } // 请求新闻数据 @Override public void requestNewsData() { // 当数据请求完成后的回调方法 newsView.showProgress(); newsModel.getNewsData(new OnReqNewsDataFinishedListener() { @Override public void onSuccess(final ArrayList data) { /* onSucces()方法是处理数据的子线程处理完数据后回调的方法,所以onSuccess()是在子线程运行的, 故在该房中更新UI时要用handler */ handler.post(new Runnable() { @Override public void run() { if (newsView != null) { newsView.hideProgress(); newsView.setListItems(data); } } }); } @Override public void onFailed() { handler.post(new Runnable() { @Override public void run() { if (newsView != null) { newsView.hideProgress(); newsView.showMessage("请求错误"); } } }); } }); } }
  1. model加载数据完成后调用presenter中的回调方法返回数据加载完成情况
/**
 * 
 *     author : 杨丽金
 *     time   : 2017/12/27
 *     desc   :
 *     version: 1.0
 * 
*/ public class NewsModelImpl implements NewsModel { @Override public void getNewsData(final OnReqNewsDataFinishedListener listener) { // 开启一个线程,模拟获取数据过程 new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(2000); ArrayList data = new ArrayList(); for(int i=0;i<8;i++) { data.add("item" + i); } int i=1/0; if (listener != null) { listener.onSuccess(data); } } catch (InterruptedException e) { e.printStackTrace(); listener.onFailed(); }catch (Exception ex){ ex.printStackTrace(); listener.onFailed(); } } }).start(); } }
  1. presenter知道数据加载情况(加载成功或失败或其他意外情况)后,调用view的接口指使view完成界面跳转等操作
/**
 * 
 *     author : 杨丽金
 *     time   : 2017/12/27
 *     desc   : presenter是model和view之间的桥梁,它不做具体操作,view划分model才是操作的具体执行者
 *     version: 1.0
 * 
*/ public class NewsPresenterImpl implements NewsPresenter { // presenter中持有View引用 private NewsView newsView; // presenter中持有model引用 private NewsModel newsModel; // 消息处理者 private Handler handler; public NewsPresenterImpl(NewsView newsView) { this.newsView = newsView; // 在构造函数中初始化变量 newsModel = new NewsModelImpl(); // 表示该handler要用主线程的Looper,将消息发送到主线程的MessageQueue中处理消息 handler = new Handler(Looper.getMainLooper()); } // 请求新闻数据 @Override public void requestNewsData() { // 当数据请求完成后的回调方法 newsView.showProgress(); newsModel.getNewsData(new OnReqNewsDataFinishedListener() { @Override public void onSuccess(final ArrayList data) { /* onSucces()方法是处理数据的子线程处理完数据后回调的方法,所以onSuccess()是在子线程运行的, 故在该房中更新UI时要用handler */ handler.post(new Runnable() { @Override public void run() { if (newsView != null) { newsView.hideProgress(); newsView.setListItems(data); } } }); } @Override public void onFailed() { handler.post(new Runnable() { @Override public void run() { if (newsView != null) { newsView.hideProgress(); newsView.showMessage("请求错误"); } } }); } }); } }

注意

  1. 在model中开启了子线程进行数据处理,处理完成后回调presenter中的onSuccess()和onFailed()方法,故onSuccess()和onFailed()方法也是在子线程中执行,所以这两个方法中更新UI的操作要用Handler异步消息处理机制
/**
 * 
 *     author : 杨丽金
 *     time   : 2017/12/27
 *     desc   : presenter是model和view之间的桥梁,它不做具体操作,view划分model才是操作的具体执行者
 *     version: 1.0
 * 
*/ public class NewsPresenterImpl implements NewsPresenter { // 消息处理者 private Handler handler; public NewsPresenterImpl(NewsView newsView) { // 表示该handler要用主线程的Looper,将消息发送到主线程的MessageQueue中处理消息 handler = new Handler(Looper.getMainLooper()); } // 请求新闻数据 @Override public void requestNewsData() { // 当数据请求完成后的回调方法 newsView.showProgress(); newsModel.getNewsData(new OnReqNewsDataFinishedListener() { @Override public void onSuccess(final ArrayList data) { /* onSucces()方法是处理数据的子线程处理完数据后回调的方法,所以onSuccess()是在子线程运行的, 故在该房中更新UI时要用handler */ handler.post(new Runnable() { @Override public void run() { if (newsView != null) { newsView.hideProgress(); newsView.setListItems(data); } } }); } @Override public void onFailed() { handler.post(new Runnable() { @Override public void run() { if (newsView != null) { newsView.hideProgress(); newsView.showMessage("请求错误"); } } }); } }); } }

代码地址

有列表的Activity Demo

参考文献

Android MVP架构的自述

你可能感兴趣的:(MVP使用示例)