Реализация надежной постоянной функции отмены / возврата - PullRequest
1 голос
/ 28 октября 2010

Я пишу редактор растровых изображений, в котором я использую шаблон команд для представления действий, которые преобразуют документ. Я сохраняю все команды, выполненные до сих пор, в списке и, чтобы реализовать отмену, я возвращаю документ в его первоначальное состояние и затем воспроизводю все, кроме последней команды.

Я бы хотел, чтобы в моей системе отмены / повтора была предусмотрена следующая функция: когда пользователь закрывает редактор и возвращает его, документ , включая доступные команды отмены и повтора , должен быть восстановлен до его состояния. был, когда пользователь ушел.

Я реализую это для Android, где вашему приложению может быть уделено очень мало внимания, прежде чем оно будет удалено из памяти, например, если пользователь получает телефонный звонок. Кроме того, некоторые из моих команд, например, список всех координат x, y, нарисованных пользователем, так что это может занять несколько минут для сохранения на диск.

Моя текущая идея заключается в следующем:

  1. Когда выполняется новое действие, объект команды добавляется в список S для команд, которые необходимо сохранить на диск.
  2. Используется фоновый поток, который будет постоянно принимать команды из списка S и сохранять их на диск. Постфикс используемых имен файлов будет пронумерован по порядку. Например, если пользователь заполнил экран, затем нарисовал 2 круга, командные файлы могут называться FillCommand1.cmd, DrawCircleCommand2.cmd, DrawCircleCommand3.cmd.
  3. Периодически мы сохраняем команду «checkpoint», целью которой является сохранение полного состояния документа, чтобы, даже если один из файлов .cmd был поврежден, мы могли восстановить последнюю версию документа.
  4. Когда пользователь выходит из приложения, фоновый поток пытается завершить сохранение всех команд, которые он может (но он может быть убит).
  5. При запуске мы ищем самый последний файл .cmd, представляющий контрольную точку, которую мы можем успешно загрузить. Все файлы .cmd, которые мы можем загрузить после этого (то есть некоторые файлы могут быть повреждены), попадают в список команд повтора, все файлы .cmd, которые мы можем загрузить между первой загруженной контрольной точкой и самой старой контрольной точкой, которую мы можем загрузить, входят в список отмен .

Я хочу, чтобы предел отмены составлял около 20 или 30 команд назад, поэтому мне нужна дополнительная логика для отбрасывания команд, удаления файлов .cmd, и мне нужно беспокоиться о многопоточности. Эта система кажется довольно сложной и потребует много испытаний, чтобы убедиться, что она не ошибается.

Есть ли что-нибудь в Java или Android, что может помочь сделать это проще? Я заново изобретаю колесо? Может быть, база данных будет лучше?

Ответы [ 2 ]

0 голосов
/ 28 октября 2010

Вместо того, чтобы возвращаться к оригиналу и затем выполнять все действия, рассмотрите возможность сделать Команды обратимыми.Таким образом, если вы когда-нибудь решите увеличить размер своей истории отмен, вы не будете представлять потенциальную задержку при отмене.В качестве альтернативы, как отмечает Джаред Апдайк, ваше приложение может извлечь выгоду из кэширования результатов рендеринга в ближайшем прошлом и будущем.

Я думаю, вы слишком усложняете свое решение на основе файловой системы.Если вы хотите сохранить резервную копию всей истории текущего рабочего документа, вы должны просто оставить небуферизованный журнал открытым в режиме добавления и записывать в него действия.Журнал должен быть связан с конкретным экземпляром приложения и редактируемым файлом, поэтому вам не нужно беспокоиться о том, что другой поток наступит вам на ноги.Загрузка из этого журнала должна быть очень похожа на загрузку из обычного файла сохранения.Просто отбрасывайте последнее прочитанное действие, когда встречаете действие отмены.

0 голосов
/ 28 октября 2010

Ну, ваш код, вероятно, является обязательным по своей природе, когда состояние приложения изменяется на месте действиями пользователя.Это, вероятно, быстро и просто.Отмена - это в основном путешествие во времени, и если вы закроете старые состояния, изменив состояние на месте, вам придется хранить либо рецепты для перерасчета в обратном порядке, либо историю, которая может пересчитать его вперед.

Как вы сказали, выможет сохранять действия и исходное состояние и воспроизводить их вперед (останавливаясь на новой точке в истории, которую выбирает пользователь), но это означает, что отмена одного действия может привести к воспроизведению n действий.Один из подходов заключается в сохранении сохраненных копий состояний в списке истории, чтобы вы могли сразу же перейти к заданному состоянию.Чтобы избежать использования слишком большого объема ОЗУ или хранилища, если ваша система умна, она может обнаружить ближайшее (ненулевое) сохраненное состояние в истории и пересчитать эти несколько шагов вперед (при условии, что у вас есть все необходимые действия - это предполагает, что действиямаленький и состояние большое (r)), пока не будет достигнуто правильное состояние.Таким образом, вы можете начать удалять старые сохраненные состояния (удалить или установить в ноль) (сбросить состояние на основе функции стоимости, обратно пропорциональной тому, как далеко назад во времени находится состояние), быстро отменяя недавнее прошлое, и память /хранение эффективно для древней истории.У меня был успех с этим методом.

...