结合实际业务场景聊一聊MVP模式的应用
MVP模式出来不是一天两天了,不过最近开始比较热(当然也可能是我最近才发现……)。
考虑到部分公司和团队还在使用Eclipse开发兼容Android2.2的应用,需要AndroidStudio1.3才支持的MVVM模式自然是不太适用,因此还是采用兼容度比较高的MVP模式比较适合。
MVP的基础知识不必多说,Model模型访问数据,View视图显示数据,Presenter表示器负责连接两者,前人已经有过不少好文章了,随手丢几个:
对MVC、MVP、MVVM的理解、Android中的MVP、Introduction to Model View Presenter on Android
但是大部分文章的问题在于例子过于基础,基本上都是简单的输入输出保存读取,理解基本概念是够了,看完觉得哇塞这个好屌我要用到我的项目里,但是一敲代码我你就抓瞎了。
比如信息访问的例子,用户输入数据,点击按钮,View层捕获事件,调用Presenter执行保存逻辑,通过Model建立Domain,固化数据到数据库。
但是看完了你一琢磨。
嗯?这跟MVC有区别吗?
然而并没有什(
于是我们来讨论几个问题。
1. 谁来做异步?
某篇讲解MVP的文章下有人问了,『我的Model层是异步访问网络的,(并不能马上返回数据,)那样Presenter要怎么更新View呢?难道用回调接口的方式吗?』
看到的时候我还真思考了一下。
首先代入传统的思考方式,在编写上帝Activity类的时候我们是怎么做异步的?线程在哪里start,AsyncTask在哪里execute?
直接在事件逻辑里执行异步好像是比较常规比较蠢的办法,线程执行完毕通过Handler之类的线程间通讯传递执行结果,AsyncTask则在onPostExecute里直接在主线程处理。
多说一句,AsyncTask写起来真丑啊……
如果要做得比较高端则可以用上第三方框架,比如Volley,各种ImageLoader等等,这类框架要么是通过监听器返回结果,要么是通过主线程的回调函数返回结果,要么像ImageLoader一样,干脆把返回结果的过程给封装住。
那么话说回来,你告诉我,
谁TM干不TM行啊!(╯°Д°)╯( ┻━┻
┬—┬ ノ( ' - 'ノ)只要不让View来做
让谁TM干不TM一样啊!(╯°Д°)╯( ┻━┻
2. 弹Dialog/Toast/PopupWindow到底是UI操作还是后台逻辑?
首先把思路从UI线程和后台线程的区别里抽离出来,这个和问题是两回事。
这些东西由UI来显示,看似应该放在View层,但是创建的过程又仿佛是业务逻辑,放在View层显得啰嗦,似乎应该放到Presenter层。
细化到创建的过程,以Dialog为例,好像设置内容的部分属于UI,处理内容操作和监听事件属于后台逻辑。
那把创建放到View层,处理内部View的逻辑和监听到按钮事件的时候再调用Presenter中的接口?似乎传递来传递去又太麻烦。
还是根据实际业务场景来决定吧。
对于操作简单的对话框,比如退出确认,就在View里创建并显示,事件交由Presenter来处理。
对于比较麻烦的,比如内部显示了一个复杂的视图,子View之间还会互相联动,比如拖动进度条改变文字显示之类的,能在View层直接处理就不要往Presenter里再多跳一次。如果逻辑复杂,不如干脆把创建放到Presenter里,只通过View接口来做显示算了。
3. 上下文怎么搞?
首先明确一条原则:理想化的Presenter是纯Java实现的。
当然实际情况下尽可以灵活一点,不必要这么轴。
这条原则描述的是MVP模式的优越性之一,即是业务逻辑可以脱机进行单元测试。
通过单独实现了View接口和Model接口的测试用例,可以在不依赖Android环境的情况下对Presenter进行测试。
但是,也不可能把所有Android代码都扔到View和Model里去,比如startActivity操作属于Activity类,一些API的调用还需要Context实例。
尽管我们知道View层无非也就是Activity、Fragment和View这几个类的各种实现,而且它们理论上都能拿到上下文,但是就因为这样就把这些需要上下文的操作丢还给View层来执行吗?
我觉得大可不必。
只要能避免Presenter长时间持有上下文导致出现内存泄露的可能性,该交给后台的还是由后台来做。
我的做法是在View层接口里加入上下文的访问函数,Presenter只在需要的时候作为临时变量调用,内部不保存。
使用全局ApplicationContext也是一个办法,至于用这个实例到底好不好暂且按下不表。
…………那……
4. Adapter算前台还是后台?
Adapter需要访问数据,需要执行业务逻辑,需要将数据绑定到视图。
Adapter在MVP模式里站那个位置?
如果要绑定Presenter的话应该绑在Adapter上还是getView方法里初始化的那个View对象上?
是不是觉得这种情况有点似曾相识?
这是不是毅种循环?
『ActivityAdapter是不是Controller?』
『那个……』
『你有没有见过超过五千行的ActivityAdapter?』
『…………呃……』