摘要:
以前不明白什么是接口,怎么定义接口,使用接口有什么意义,随着开发的深入,认识的提升,对接口的有了更深的理解。TeachCourse阅读Android开发文档或源码已不是啥难事,理解接口最重的三个步骤:1.设置接口,在使用到接口抽象方法的地方,定义接口对象并声明set方法,最后调用接口方法;2.定义接口,接口可以是内部类或独立类;3.实现接口,执行监听,事件处理。
任何的一个控件或多或少都对外提供设置接口的方法,通过接口对象调用接口方法,最后监听接口是否发生了改变,这是一个抽象的概念,如果不理解建议看一下《深入理解接口的定义和意义》或《如何重用接口多个抽象方法中的一个或多个?》,MVP的核心在TeachCourse看来就是熟练运行接口,深入理解接口的运用,对于阅读源码或使用MVP设计模式非常有帮助。下面先看一个实际开发中,使用接口监听的例子
一个PullToRefreshListView的每个item是一条详细订单信息,有“忽略”和“抢单”按钮,在已抢单界面,点击“确认收货”后改变按钮的状态,这该怎么实现呢?
PullToRefreshListView使用BaseAdapter子类绑定数据,item的视图和Activity分开,进行“忽略”或“抢单”的操作在Activity或Fragment中处理,完成后调用notifySetDatachanged()刷新列表,如果使用MVP设计模式,会在Presenter中处理。
点击item上的按钮时,我们设置了接口,在Activity或Fragment中实现接口行进监听,然后“忽略”或“抢单”,完成和后台交互后,notifyDataSetChanged刷新列表,这个还算是比较好理解的,但想要在抢单界面中点击“确认收货”后,改变按钮状态,这又得设置多一次接口,实现改变按钮状态的操作,具体的逻辑,看一下代码:
- /**
- *isWarn为空,为确认收货,否则反之
- */
- if (!TextUtils.isEmpty(isWarn)) {
- viewHolder.sureBtn.setText(context.getResources().getString(R.string.sure_get_order));
- viewHolder.sureBtn.setClickable(false);
- viewHolder.sureBtn.setEnabled(false);
- }else
- viewHolder.sureBtn.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (onClickImageView != null) {
- /**
- * 接口监听确认收货是否完成
- */
- onClickImageView.onClick(v, position);
- fragment.setICompleteOrder(new ICompleteOrder() {
- @Override
- public void isCompleted(boolean isCompleted,int position) {
- /**确认收货完成,将isWarn字段设为1,表示已确认;为空,表示未确认收货*/
- list.get(position).setIsWarn("1");
- notifyDataSetChanged();
- }
- });
- }
- }
- });
在这个例子中,如果你理解起来不是什么难事,说明你对接口的理解还是很不错的,能够理解接口的定义和意义,那么我们开始Android开发中使用MVP设计模式之旅。
一、MVP实例
MVP全称Model,View和Presenter,三者之间相互关系,有点像三角恋的关系,Model喜欢Presenter,Presenter喜欢View,View喜欢Activity或Fragment,于是Model和Presenter互相通信,Presenter和View互相通信,View和Activity或Fragment互相通信,如下图:
将Model、Presenter和View设置成接口,符合Java面向抽象的设计思想,一个Model或一个Presenter可以有多个实现类,完成多种功能扩展,易于维护,方便测试,利于复用,这也是MVP在Android开发中越来越重要的原因之一。
在上面的例子中,获取后台订单内容,在PullToRefreshListView列表中展示,采用MVP的设计模式,IView接口声明一个抽象方法showOrder(),Activity实现IView接口,执行监听操作,简化只剩下两句刷新UI界面的代码:
- @Override
- public void showOrder(List<OrderBean> list){
- mOrderDataList.addAll(list);
- mAdapter.notifyDataSetChanged();
- }
从后台获取数据并写入数据库在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(),代码如下:
- @Override
- public void gainOrder(){
- /**
- *loadData从本地或网络加载订单数据
- */
- List<OrderBean> result=mIModel.loadData();
- /**
- *将返回的结果传入IView接口,最终实现接口IView的Activity或Fragment执行监听
- */
- mIView.showOrder(result);
- }
Presenter同样只有两行代码,联系了IView和IModel。
最后,剩下的只有IMdoel的逻辑处理:如何从网络获取数据,怎么写入数据库或缓存?读取的时候先判断缓存是否有数据,有数据优先从缓存读取,没有数据重新请求服务器获取。创建IModelImpl实现IModel接口,关键代码:
- @Override
- public List<OrderBean> loadData(){
- List<OrderBean> result=getDataByLocal();
- if (result.size==0)
- result=getDataByNetwork();
- return result;
- }
以后需要重写loadData抽象方法的逻辑,那就很方便了,重新声明一个IModelImpl2实现类,重写loadData方法就可以了。在TeachCourse的项目开发中,IModel实现了重用的功能,在上面的例子,有“未抢单”和已抢单的两个列表,显然只是请求的参数有变化,其它的都是一样的,在IView和IPresenter接口分别添加抽象方法showCompletedOrder和gainCompletedOrder,而IModel则不需要改变:
- @Override
- public void gainCompletedOrder(){
- /**
- *loadData从本地或网络加载订单数据
- */
- List<OrderBean> result=mIModel.loadData();
- /**
- *将返回的结果传入IView接口,最终实现接口IView的Activity或Fragment执行监听
- */
- mIView.showCompletedOrder(result);
- }
通过这个例子,我们看到,Presenter对View是完全解耦合的,Presenter依赖的是IView抽象,实现IView的Activity或Fragment更新UI,当UI界面发生改变时,只需要重新实现IView接口即可快速地和Presenter协作起来,成本低,效率高,Activity或Fragment变得轻量级,职责单一,功能简单,易于维护。
你可能感兴趣的文章
转载请注明出处: https://www.teachcourse.cn/2189.html ,谢谢支持!