Помилка роботи файлів при збої / вбивстві гри ОС / Користувача в Android


13

Моя гра зберігає свій стан після фіксованого інтервалу у файлі у внутрішній пам’яті гри та додатків. Коли мою гру вбивають або розбивають користувач або ОС відповідно, ми записуємо поточний стан гри у цей файл. Запис файлів після інтервалу виправлення працює нормально, але коли гру або програють ОС або користувач, система збиття файлів закінчується. Помилка роботи призводить до неповного стану гри або порожнього стану гри, тобто жодних даних, записаних у файл, взагалі немає. Я спробував декілька рішень за допомогою сервісу Android, на випадок, якщо служба NON STICKY, служба загине за допомогою програми. З іншого боку, якщо сервіс STICKY, то він перезапускається, але наміри, які були додані спочатку до служби, є нульовими або новими.

Питання полягає в тому, як я можу повністю зберегти свої дані (може бути ~ 2-3 Мб) повністю у файлі на внутрішньому сховищі, коли мою гру / додаток вбиває користувач / ОС?


Ви повинні обробляти свої SIGTERM та SIGKILL (ну, можливо, це не SIGKILL, Android, ймовірно, використовує SIGTERM). (Не встигайте дослідити / написати повну відповідь, але це основна ідея.)
Джон Гамільтон

2
@JohnHamilton SIGKILL не можна обробляти за визначенням.
Darkhogg

@Darkhogg Ну, не в Unity, це точно. (Я змінив ядро ​​Linux в один момент для проекту для цієї конкретної мети, і, безумовно, можна дозволити програмам обробляти SIGKILL)
Джон Гамільтон

Відповіді:


20

Я б запропонував написати свій стан збереження подвійним буферизованим способом, як це було звичайно для заголовків консолей у минулому (де вам довелося впоратися з видаленням картки пам'яті в середині запису, а записи були повільними).

Зберегти:

  • Якщо файлів немає, запишіть стан у файл A
  • Якщо A існує, напишіть на B
  • Якщо A і B існують обидва, знайдіть, хто з них старший, видаліть його, а потім напишіть до цього

Завантажте:

  • Якщо і A, і B існують, спробуйте завантажити новіші з двох. Якщо це не вдається (оскільки файл неповний або пошкоджений), видаліть його та завантажте інший
  • Якщо існує лише одна, завантажте її
  • Якщо обидва є пошкодженими, повідомте користувача, що їх стан збереження було безповоротним (як, мабуть, ви вже повинні)

Цей потік буде працювати над тим, щоб у вашому сховищі завжди був принаймні один дійсний збереження, навіть якщо додаток загинув із середини запису. Гравець не отримає жодних змін у ігровому стані з попереднього збереження, якщо трапиться така помилка, але їм не доведеться починати заново.

Крім того, вам слід економити одразу після ключових подій (наприклад, придбання через додаток), крім збереження інтервалу, щоб мінімізувати вікно вразливості, коли аварія / вбивство призведе до втрати цієї ключової події. Це також захист від ігрових подвигів (наприклад, насильницьке вбивство програми після втрати життя, тому що ви знаєте, що повернетеся до ігрового стану до того, як втратили життя, і отримаєте спробувати знову). Звичайно, якщо це зробити, ви повинні захистити інтервал збереження логікою, яка говорить: "Якщо збереження вже триває, не намагайтеся знову починати збереження".


Дякую MrCranky, це часткове рішення моєї проблеми, як я можу зберегти дані останнього сеансу, тобто перед вбивством програми / гри? Наприклад, він зробив додаток у програмі та вбив програму.
Файсал Імран

12
Вам навіть не потрібні два файли. Напишіть на B, якщо і лише в тому випадку, якщо запис було успішним, видаліть A і перейменуйте B в A., java.nio.file.Files.move(Path source, Path target, CopyOption... options)можна перейменувати і перезаписати як атомну операцію.
Полігном

6
@ Polygnome: Зауважте, що у разі відключення електроенергії це не завжди надасть гарантії, які ви очікуєте, якщо ви не зателефонуєте sync()у файл B перед тим, як перенести його по файлу A (навіть тоді немає повних гарантій, але sync()це досить добре).
Дітріх Епп

1
@FaisalImran Збережіть дані відразу після важливої ​​операції, наприклад, після IAP. Якби операцію було перервано вимкненням телефону, я думаю, це ніколи не братиме грошей у людини. Але про всяк випадок, ви можете захотіти зберегти дані його рахунку при покупці на якійсь платформі як спробу щось придбати. Потім пізніше ви можете порівняти свій прибуток із цими даними та побачити, чи справді ця людина щось купив. А потім відкрийте для нього цю функцію через онлайн-сервіс, який ви використовуєте для збереження всіх даних. Якщо ви використовуєте локальну економію для IAP, це навіть гірше, ніж ця проблема.
Відвертий Місяць _Max_

1
Нарешті, хоча це не може вирішити всі ваші проблеми, я б сказав, що ваша проблема не повністю вирішена. Ви не можете підтримувати як "користувач може вбити мою програму в будь-який час", так і "жодні дані не повинні втрачатися ніколи", тому що завжди відбудеться вікно після події, але до того, як вона зберігатиметься для зберігання, де користувач може вбити додаток і втратити дані.
MrCranky

3

Android вбиває програми лише тоді, коли вони знаходяться у фоновому режимі. Чи дійсно потрібно оновити ваші дані про ігри, коли програма знаходиться у фоновому режимі, чи ви можете зупинити оновлення даних, поки додаток не повернеться на перший план? Можливо, ви зможете відкласти оновлення навіть у грі для багатьох гравців, якщо ви зможете схопити історію подій або навіть лише поточний стан, коли додаток повернеться на перший план. Це, напевно, варто дивитись на те, щоб зробити це заради ефективності процесора, мережі та акумулятора.

Якщо користувач вбиває вашу програму, запущені служби повинні отримати дзвінок на onTaskRemoved. Я не знаю, що трапилося б, якби ви спробували зробити багато способів обробки цим методом. Я очікую, що якщо Android не повернеться протягом певного часу, Android стане kill -9вашим додатком.


додаток не потребує оновлення у фоновому режимі, але програма повинна зберігати свої дані, тобто json-файл, перш ніж перейти до фону або знищити.
Фейсал Імран

ви маєте право на методTaskRemoved зателефонує, але час, необхідний для збереження файлу, більше, або ми можемо сказати, час обчислень великий. Коли користувач вбиває додаток, цей спосіб буде зупинений.
Файсал Імран
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.