Android view vs View vs 界面先区分一下Android View、View、界面的区别
切换界面界面间的切换可以是两个Fragment、两个Activity、打开对话框、启动新Activity等等。当然切换的具体实现原理不属于这篇文章的内容,而进行切换操作则是Presentation层的职责。Presenter应该知道要做什么,而它的实现类要知道怎么完成。在这个例子中,要做的就是切换界面,完成方式就是启动新的Activity。 但这样会有一个问题。Presentation层是纯java代码,所以Presenter中不应该有任何与安卓相关的代码。那怎么完成界面的切换呢?通过抽象。这里可以写一个只有一个navigate()方法的接口NavigationCommand。在需要时我们在Presenter中调用这个接口的navigate()方法,然后在Activity中实现这个接口。假设要从Activity A切到Activity B,那么流程如下: 代码长这样: View层ActivityA.java
ToActivityB.java
Presentation层NavigationCommand.interface
PresenterA.java
这样我们就可以将VP两层解耦。这里将切换到一个Activity的代码提取出来,可以复用,我们可以通过注入NavigationCommand方法来测试Presenter,而且就算要跳转的页面变了,Presenter的代码也不变。这也符合Open Close原则。 另一个问题就是当一个Presenter中出现多个NavigationCommand时,构造方法就开始变得诡异了。
在这里初始化Presenter的类很难搞清楚两个NavigationCommand之间的顺序,似乎只能通过名字来辨识,这里其实可以再写一个接口继承NavigationCommand来专门管理一类特定的切换,或者如果你使用依赖注入框架的话也可以指定参数的类型。 有时需要在切换界面时传递一些参数,这时就要改动一下NavigationCommand的代码:
这样只需要在Presenter中在调用navigate()方法之前调用设置参数的方法就行了。 这个idea归功于Pedro的项目EffectiveAndroidUI(https://github.com/pedrovgs/EffectiveAndroidUI/blob/1dadd276b094dffed2ae2e88602925c173ab59d7/app/src/main/java/com/github/pedrovgs/effectiveandroidui/ui/viewmodel/action/ActionCommand.java) 一个界面中有多个ViewAndroid中一个View可能由不同的组件实现,但这不影响Presenter。那一个界面中可以有多个View吗?当然可以!那如何在一个Activity中写多个View/Presenter呢?下面以Browse Spotify界面为例分析。
不过为什么要分开呢?分开写View/Presenter与合在一起写一个有所有操作的Presenter有多大区别呢?这时要考虑到谁负责填充这些View,以及如何复用组件。这三个组件是完全不同的组件,有不同的功能、操作与逻辑代码,它们都会在其他界面被用到。 所以一个界面可以有多个View/Presenter,因为一个界面可能包括了许多组件而且可能负责许多操作,这个是设计师的事。要记住每一项责任就是一个潜在的发生改变的原因,而上述这三个View都很可能发生改变。 一个View可以有2个实现类吗?当然!对同一个Presenter的View可以有多个实现类。再以Spotify举例,刚才的界面的下方有一个正在播放的栏,当你点击时出现下面这个界面:
MVP架构总结一下前面的内容:
下面来看一下其他的概念。 Presenter生命周期下面这张截图来自Citymapper,当你点击“带我去那”按钮的时候就会打开一个让你选择开始结束位置的界面。
如果此时设计改了,不再是两个tab了,而是一个分为两步的表单。这是需要将选择开始位置的Fragment替换为选择结束位置的Fragment。View层的代码改变了,但Presenter不变。设计可以千变万化,再比如分屏显示两个地图,但都不会改变Presenter的代码。 那么Presenter的生命周期如何呢?这取决于与Presenter对应的组件。 我们先看一下Selltag应用,这是一个二手交易应用。下面是旧版应用创建商品的截图:
在第一步中,先给商品添加一些图片。第二步中要填写标题、描述和价格。最后点击发布按钮,商品就进入交易市场了。 在我给这个表单建立的模型中只有一个Presenter:“PublishProductPresenter”。这个Presenter代表了整个“发布商品”的概念。而这个表单在平板上该如何显示呢?或许这三步可以整合在一个界面中,毕竟屏幕变大了。但不要看到界面变了就改架构,这里只是View层变了,因为Presentation层只需要处理用户事件,代码不变。 这里有一个问题是如果只用一个Presenter的话,在不同的界面间如何传递数据呢?是在后面界面的Presenter保留前面界面Presenter的引用吗?还是创建一个Presenter让三个Activity共享?这样出了bug很难调试啊。这里也可以将这三个界面写成Fragment放在一个Activity里。 Presenter状态当屏幕方向改变的时候,Activity和Presenter都会被销毁,所以要不要给Presenter设置状态呢?其实添加Presenter状态还不如修改一下Model层的代码。为什么这么讲,请看这个例子:
回调地狱Callback HellCallback Hell是人们谈论Presentation层时经常讨论的问题。许多有关回调地狱的问题都是因为Presenter的任务太重。不要把Model层的任务放在Presenter里,Presentation层只应该调用Model层的方法,由Model层完成诸如同步等操作。在使用RxJava或Jdeferred等第三方库之前请思考是真的需要还是只是必须通过这些库把整个系统粘在一起。 为了描述上述问题我造了一个例子:想象一个系统,只在服务端返回true时加载并展示一个产品组成的列表。下面第一个图所展示的流程主要在错在两个地方:第一是Presenter不应该知道服务端返回的flag,这个是Model层的事。第二是presentation层因为要负责各种同步之类的事情导致代码变多。 改进之后的流程图: 这样一来两个问题就解决了,而且如果未来不再需要flag了就只需要修改action就行了。 结论设计Presentation层的架构很简单,但你需要知道什么代码归Presenter什么归Model。当你有一个巨型Presenter时,想想真的是界面需要响应的事件太多,还是你的Presenter干了Model的事。 本文作者:Christian Panadero 译者:程大治 原文地址: http://panavtec.me/modeling-presentation-layer/ 本文由译者授权发布于本公众号。 点击阅读原文也可以查看英文原文。 本文转载自:微信公众账号 - 移动开发前线,版权归原作者所有! |
|
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系
[邮箱地址] 删除
|