Android 实现健壮的持久撤消/重做功能

Android 实现健壮的持久撤消/重做功能,android,design-patterns,mobile,undo,Android,Design Patterns,Mobile,Undo,我正在编写一个位图编辑器,其中我使用命令模式表示将转换文档的操作。我将目前为止执行的所有命令都保存在一个列表中,为了实现撤消,我将文档恢复到初始状态,然后重播除最后一个命令以外的所有命令 我希望我的撤消/重做系统具有以下功能:当用户关闭编辑器并返回时,文档(包括可用的撤消和重做命令)应恢复到用户离开时的状态 我正在为Android系统实现这一功能,如果用户接到电话,你的应用程序在从内存中清除之前几乎不会收到任何通知。此外,我的一些命令是,例如,用户绘制的所有x,y坐标的列表,因此可能需要一些时间

我正在编写一个位图编辑器,其中我使用命令模式表示将转换文档的操作。我将目前为止执行的所有命令都保存在一个列表中,为了实现撤消,我将文档恢复到初始状态,然后重播除最后一个命令以外的所有命令

我希望我的撤消/重做系统具有以下功能:当用户关闭编辑器并返回时,文档(包括可用的撤消和重做命令)应恢复到用户离开时的状态

我正在为Android系统实现这一功能,如果用户接到电话,你的应用程序在从内存中清除之前几乎不会收到任何通知。此外,我的一些命令是,例如,用户绘制的所有x,y坐标的列表,因此可能需要一些时间才能保存到磁盘

我目前的想法如下:

  • 执行新操作时,命令对象将添加到需要保存到磁盘的命令列表中
  • 使用一个后台线程,该线程将持续从列表中获取命令并将其保存到磁盘。所用文件名的后缀将按顺序编号。例如,如果用户填充屏幕,然后绘制2个圆圈,则命令文件可能称为FillCommand1.cmd、DrawCircleCommand2.cmd、DrawCircleCommand3.cmd
  • 我们定期保存一个“checkpoint”命令,其目的是存储完整的文档状态,以便即使其中一个.cmd文件损坏,我们也可以恢复文档的最新版本
  • 当用户退出应用程序时,后台线程会尝试保存所有可以保存的命令(但可能会被杀死)
  • 启动时,我们会查找最新的.cmd文件,该文件表示可以成功加载的检查点。在此之后,我们可以加载的所有.cmd文件(即某些文件可能已损坏)都会进入“重做命令”列表,我们可以在加载的第一个检查点和可以加载的最旧检查点之间加载的所有.cmd文件都会进入“撤消”列表

  • 我希望撤销限制是大约20或30个命令,所以我需要额外的逻辑来丢弃命令、删除.cmd文件,并且我必须担心多线程行为。这个系统看起来相当复杂,需要进行大量测试以确保不会出错


    Java或Android中是否有任何东西可以帮助实现这一点?我在哪里重新发明轮子?也许数据库会更好?

    好吧,您的代码在本质上可能是必需的,应用程序的状态由用户的操作修改到位。这可能是快速而直接的。撤销基本上是一种时间旅行,如果你通过修改状态来打破旧状态,你将不得不存储反向重新计算的配方,或者可以向前重新计算的历史


    正如您所说,您可以存储操作和初始状态并向前播放(在用户选择的历史记录中的新点停止),但这意味着撤消一个操作可能会导致n个操作重播。一种方法是将保存的状态副本存储在历史记录列表中,以便可以立即跳转到给定状态。为了避免使用过多的RAM/存储,如果您的系统很聪明,它可以检测历史记录中最近的(非空)保存状态,并向前重新计算这几个STPE(假设您有所有需要的操作——假设操作很小,状态很大(r)),直到达到正确的状态。通过这种方式,您可以开始消除旧的保存状态(删除或设置为null)(根据与状态的时间长度成反比线性关系的成本函数删除状态),使最近的撤销快速,并使古代历史的内存/存储高效。我已经成功地使用了这个方法。

    ,而不是恢复到原来的,然后执行所有的动作,考虑使命令可逆。这样,如果您决定增加撤消历史记录的大小,就不会在撤消时引入延迟的可能性。或者,正如Jared Updike所指出的,在不久的过去和将来,您的应用程序可能会从缓存渲染结果中受益


    我认为您的基于文件系统的解决方案过于复杂了。如果要维护当前工作文档的整个历史记录的备份,只需在附加模式下打开一个无缓冲日志,并将操作记录到其中。日志应该与正在编辑的应用程序和文件的特定实例相关联,这样您就不必担心另一个线程会踩到您的脚。从该日志加载应该与从普通保存文件加载非常相似。只要在遇到撤消操作时放弃上次读取操作即可。

    “此系统看起来相当复杂,需要大量测试以确保不会出错。”欢迎使用现实世界中的应用程序。函数式编程风格可能会有所帮助(保留旧值——无法解决应用程序退出/持久性问题),但这样可能会出现内存使用问题。“…一个数据库…”这可能有助于提高速度,但从根本上说,这并不能让它变得更容易,我不相信。除非你有一个内置了历史记录的git数据库。大多数位图编辑器操作都是破坏性的,所以函数式编程方法在我看来帮不了什么忙。对。但是,如果您的代码是执行(位图、操作)返回NewBitmap,那么您将拥有自己的状态。当然,这会强制复制可能不需要的位图。仅仅因为典型的方法是破坏性的并不意味着没有其他方法(即使在大多数情况下,手工复制的破坏性可能更好)。选择要存储的状态的方法可能是您想要的。函数式编程的另一个方面是共享组件的丰富持久数据结构集,因此实际上不必显式复制状态。比较命令式方法:hash-ta