深入理解接口的定义和意义(2)之MVP实例

2016-12-11 09:37 评论 0 条

摘要:

以前不明白什么是接口,怎么定义接口,使用接口有什么意义,随着开发的深入,认识的提升,对接口的有了更深的理解。TeachCourse阅读Android开发文档或源码已不是啥难事,理解接口最重的三个步骤:1.设置接口,在使用到接口抽象方法的地方,定义接口对象并声明set方法,最后调用接口方法;2.定义接口,接口可以是内部类或独立类;3.实现接口,执行监听,事件处理。

任何的一个控件或多或少都对外提供设置接口的方法,通过接口对象调用接口方法,最后监听接口是否发生了改变,这是一个抽象的概念,如果不理解建议看一下《深入理解接口的定义和意义》或《如何重用接口多个抽象方法中的一个或多个?》,MVP的核心在TeachCourse看来就是熟练运行接口,深入理解接口的运用,对于阅读源码或使用MVP设计模式非常有帮助。下面先看一个实际开发中,使用接口监听的例子

1210-2356-how-to-use-interface

一个PullToRefreshListView的每个item是一条详细订单信息,有“忽略”和“抢单”按钮,在已抢单界面,点击“确认收货”后改变按钮的状态,这该怎么实现呢?

1210-2358-how-to-use-interface

PullToRefreshListView使用BaseAdapter子类绑定数据,item的视图和Activity分开,进行“忽略”或“抢单”的操作在Activity或Fragment中处理,完成后调用notifySetDatachanged()刷新列表,如果使用MVP设计模式,会在Presenter中处理。

点击item上的按钮时,我们设置了接口,在Activity或Fragment中实现接口行进监听,然后“忽略”或“抢单”,完成和后台交互后,notifyDataSetChanged刷新列表,这个还算是比较好理解的,但想要在抢单界面中点击“确认收货”后,改变按钮状态,这又得设置多一次接口,实现改变按钮状态的操作,具体的逻辑,看一下代码:

  1. /** 
  2.  *isWarn为空,为确认收货,否则反之 
  3.  */  
  4. if (!TextUtils.isEmpty(isWarn)) {  
  5.             viewHolder.sureBtn.setText(context.getResources().getString(R.string.sure_get_order));  
  6.             viewHolder.sureBtn.setClickable(false);  
  7.             viewHolder.sureBtn.setEnabled(false);  
  8.         }else  
  9.             viewHolder.sureBtn.setOnClickListener(new OnClickListener() {  
  10.   
  11.                 @Override  
  12.                 public void onClick(View v) {  
  13.   
  14.                     if (onClickImageView != null) {  
  15.                         /** 
  16.                          * 接口监听确认收货是否完成 
  17.                          */  
  18.                         onClickImageView.onClick(v, position);  
  19.                         fragment.setICompleteOrder(new ICompleteOrder() {  
  20.   
  21.                             @Override  
  22.                             public void isCompleted(boolean isCompleted,int position) {  
  23.                                 /**确认收货完成,将isWarn字段设为1,表示已确认;为空,表示未确认收货*/  
  24.                                 list.get(position).setIsWarn("1");  
  25.                                 notifyDataSetChanged();  
  26.                             }  
  27.                         });  
  28.                     }  
  29.                 }  
  30.             });  

在这个例子中,如果你理解起来不是什么难事,说明你对接口的理解还是很不错的,能够理解接口的定义和意义,那么我们开始Android开发中使用MVP设计模式之旅。

一、MVP实例

MVP全称Model,View和Presenter,三者之间相互关系,有点像三角恋的关系,Model喜欢Presenter,Presenter喜欢View,View喜欢Activity或Fragment,于是Model和Presenter互相通信,Presenter和View互相通信,View和Activity或Fragment互相通信,如下图:

1210-2338-model-view-presenter

将Model、Presenter和View设置成接口,符合Java面向抽象的设计思想,一个Model或一个Presenter可以有多个实现类,完成多种功能扩展,易于维护,方便测试,利于复用,这也是MVP在Android开发中越来越重要的原因之一。

1211-0014-mvp-structure

在上面的例子中,获取后台订单内容,在PullToRefreshListView列表中展示,采用MVP的设计模式,IView接口声明一个抽象方法showOrder(),Activity实现IView接口,执行监听操作,简化只剩下两句刷新UI界面的代码:

  1. @Override  
  2. public void showOrder(List<OrderBean> list){  
  3.   
  4.     mOrderDataList.addAll(list);  
  5.     mAdapter.notifyDataSetChanged();  
  6.   
  7.     }  

从后台获取数据并写入数据库在Model中完成,Presenter传递View的需求给Model,让其应该知道应该拿什么数据或拿多少条数据回来,另外一个形象的比喻:Model就像父母亲,Presenter就像儿子,View更像爷爷奶奶,爷爷奶奶没钱花了,告诉了孙子,让孙子把消息通知爸爸妈妈,爸爸妈妈知道后,想方法挣到了钱,把钱给儿子转交给爷爷奶奶,最后爷爷奶奶高兴拿着钱去买到想买的东西。Activity拿到数据后,在PullToRefreshListView中展示,变得很明了。

Presenter拥有IView和IModel的引用,作为沟通IView和IModel的桥梁,减弱IView和IModel之间的耦合。IView告诉Presenter说“秘书,你去帮我拿10订单的数据回来吧”,Presenter回答说“好的”,然后Presenter对IModel说“业务员,今天必须签下10份订单,把数据给我”,Presenter拿到业务员签好订单转交给IView,IView的实现类调用上面的showOrder()方法刷新UI界面,IPresenter接口声明一个抽象方法gainOrder(),IPresentImpl实现接口IPresenter抽象方法;IModel接口同样声明一个抽象方法loadData(),代码如下:

  1. @Override  
  2. public void gainOrder(){  
  3.       /** 
  4.        *loadData从本地或网络加载订单数据 
  5.        */  
  6.       List<OrderBean> result=mIModel.loadData();  
  7.       /** 
  8.        *将返回的结果传入IView接口,最终实现接口IView的Activity或Fragment执行监听 
  9.        */  
  10.       mIView.showOrder(result);  
  11.   
  12.   }  

Presenter同样只有两行代码,联系了IView和IModel。

最后,剩下的只有IMdoel的逻辑处理:如何从网络获取数据,怎么写入数据库或缓存?读取的时候先判断缓存是否有数据,有数据优先从缓存读取,没有数据重新请求服务器获取。创建IModelImpl实现IModel接口,关键代码:

  1. @Override  
  2. public List<OrderBean> loadData(){  
  3.   
  4.         List<OrderBean> result=getDataByLocal();  
  5.   
  6.         if (result.size==0)  
  7.       result=getDataByNetwork();  
  8.            
  9.         return result;  
  10.   
  11.     }  

以后需要重写loadData抽象方法的逻辑,那就很方便了,重新声明一个IModelImpl2实现类,重写loadData方法就可以了。在TeachCourse的项目开发中,IModel实现了重用的功能,在上面的例子,有“未抢单”已抢单的两个列表,显然只是请求的参数有变化,其它的都是一样的,在IView和IPresenter接口分别添加抽象方法showCompletedOrder和gainCompletedOrder,而IModel则不需要改变:

  1. @Override  
  2. public void gainCompletedOrder(){  
  3.       /** 
  4.        *loadData从本地或网络加载订单数据 
  5.        */  
  6.       List<OrderBean> result=mIModel.loadData();  
  7.       /** 
  8.        *将返回的结果传入IView接口,最终实现接口IView的Activity或Fragment执行监听 
  9.        */  
  10.       mIView.showCompletedOrder(result);  
  11.   
  12.   }  

通过这个例子,我们看到,Presenter对View是完全解耦合的,Presenter依赖的是IView抽象,实现IView的Activity或Fragment更新UI,当UI界面发生改变时,只需要重新实现IView接口即可快速地和Presenter协作起来,成本低,效率高,Activity或Fragment变得轻量级,职责单一,功能简单,易于维护。

当前文章价值5.8元,扫一扫支付后添加微信提供帮助!(如不能解决您的问题,可以申请退款)

你可能感兴趣的文章

来源:每日教程每日一例,深入学习实用技术教程,关注公众号TeachCourse
转载请注明出处: https://www.teachcourse.cn/2189.html ,谢谢支持!

资源分享

Android Studio如何快速更改目录结构和包名? Android Studio如何快速更改目
Android局域网文件共享工具 Android局域网文件共享工具
Cannot run program “git.exe”: createprocess error=2,系统找不到指定的文件 Cannot run program "git.exe":
python类属性和实例属性的定义 python类属性和实例属性的定义