Android MVP - 屏幕方向 - 保留Presenter状态

3
我有一个关于Android中MVP模式的问题。我想编写自己的“应用程序核心”,其中将具有基础类来处理Presenter、View等。它必须简单、干净且“稳定”。我的想法与Mosby所提供的非常相似,我正在尝试实现类似于以下内容的东西:
1. 每个Activity都有自己的Presenter、View(与Activity通信的接口)、ViewState(持久化数据的可包装对象)。
2. 当Activity被销毁时:
- 分离View - 在bundle中保存ViewState - 取消Presenter中所有后台任务(完成时更新View的任务) - 销毁Presenter 3. 当Activity被重新创建时:
- 附加View - 恢复ViewState - 创建Presenter的新实例 - 重新启动已取消的后台任务
除了最后一个问题 - “重新启动已取消的后台任务”之外,我几乎做到了所有事情。通过一个例子讨论这个问题会更容易。假设我在Presenter中有两个方法(Retrofit 2调用):
- downloadUsers() - 从Web服务器获取用户数据,并在成功时更新View。 - downloadProject() - 从Web服务器获取项目信息,并在成功时更新View。
现在,当用户更改配置时,其中一个调用已经启动但尚未完成。如何知道在Presenter重新创建时应重新启动哪个调用?
我脑海中唯一的想法是为每个任务创建一个持久的布尔标志,在任务启动时将其设置为true,在任务完成时将其设置为false。当Presenter被创建时,我将检查每个标志并重新启动相应的调用。
你对此有何看法?如何改进?还有其他想法吗?
2个回答

1

我不知道你的用户界面是什么样子的,但对于我来说,听起来你应该将一个大的视图分成两个子视图:

  • DownloadUsersView + 由DownloadUsersPresenter管理的ViewState
  • DownloadProjectsView + 由DownloadProjectsPresenter管理的ViewState

从我的角度来看,MVP模式最好只有一个单一的模型在视图中显示(而不是像你的情况一样有两个)。通常,如果你需要在同一个视图中处理两个模型,这表明你可以将此视图和Presenter拆分为两个不同的部分。

或者,你可以将你的两个模型合并为一个单一的模型,如下所示:

class DownloadModel {
  List<User> users;
  List<Project> projects;
}

然后,您可以结合两个 Retrofit 调用创建一个 DownloadModel,当两个调用都完成时,您可以在视图中显示 DownloadModel。使用 Retrofit 和 RxJava,这很简单(请参见 combineLatest() 运算符)。在这种情况下,您不会遇到这个问题,因为您的 Presenter 只有一个 download() 方法,可以同时下载两个。如果其中一个比另一个快得多,则很可能在方向更改和重新创建 Presenter 后,更快的那个来自 Retrofit 缓存,因此这不应该对您造成太大困扰。

正如您已经说过的,您也可以开始在Presenter中跟踪哪个http调用正在执行,并在Presenter重新实例化后重新调用它们,但这意味着Presenter也必须将其内部状态保存到bundle中。Mosby没有对此进行任何规定,并假设通常没有这种需要。因此,Mosby的默认Presenter实现不提供presenter.saveInstanceState(Bundle)presenter.restoreInstanceState(Bundle)。但这并不意味着您不能/不应该这样做。您可以在Mosby和您的实现中这样做。但是,如果您开始这样做,那么您只需将先前(无mvp)坐在Activity类中的混乱代码移动到Presenter中。

因此,再次强烈建议在MVP中每个视图只有一个单一模型。

顺便问一下,为什么要重复造轮子?听起来Mosby已经提供了您要寻找的东西。Mosby还支持保留Presenter,这些Presenter可以在屏幕方向更改时生存。


谢谢你的详细回答。我主要是出于教育目的在做这个 - 我想玩一下泛型,了解Android生命周期并学习如何避免内存泄漏 :)我原本想将Presenter的状态包含在ViewState中,并在一个Bundle中保存和恢复所有内容。但现在我认为这是个坏主意。关于代码混乱的观点很好。我同意Presenter应该只处理一个模型。我在上面的例子中选了不幸的名称。让我们把它改成:downloadUsers() - Retrofit调用; storeUsers() - 将下载的数据保存在数据库中。我是否也应该使用Rx找到一个解决方案? - rafakob
@rafakob,你的问题在于你认为MVP是解决异步后台任务调度的通用解决方案。MVP的主要目的是将视图与模型分离,并在它们之间设置一个Presenter作为“协调者”。在你的例子中:将storeUsers()执行在自己的Android服务中可能是个好主意,因为你不想在屏幕方向改变时重新执行storeUser(),对吧?所以,在服务中执行storeUser(),让Presenter观察服务(使用EventBus、RxJava或其他你熟悉的方式)。 - sockeqwe

0

有许多方法和解决方案。我喜欢使用Loaders api的方法。这里有一个简单的库,你可以用来保持Presenter实例在屏幕旋转时不被销毁 https://github.com/samiuelson/Preservely


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接