Використання класу програм Android для збереження даних


112

Я працюю над досить складним додатком для Android, який вимагає дещо великої кількості даних про додаток (я б сказав, що загалом близько 500 КБ - це велика кількість для мобільного пристрою?). З того, що я можу сказати, будь-яка зміна орієнтації в додатку (якщо бути точнішим) спричинює повне руйнування та відтворення діяльності. Виходячи з моїх висновків, клас Application не має однакового життєвого циклу (тобто він, за всіма намірами та цілями, завжди створений). Чи має сенс зберігати інформацію про стан всередині класу додатків, а потім посилати на неї з "Діяльності", чи це, як правило, не "прийнятний" метод через обмеження пам'яті на мобільних пристроях? Я дуже ціную будь-які поради з цієї теми. Дякую!


8
Пам’ятайте лише про те, що дані у Вашій програмі все ще можна видалити, якщо ваш додаток вийде на другий план, тому це не є рішенням для збереження даних, які ви завжди хочете отримати назад. Він просто служить методом того, що не потрібно часто відтворювати дорогі предмети.
Шеріл Симон

2
Майра; Я не думаю, що додаток "зазвичай" видаляється (хоча, як хтось вказує пізніше у цій темі, це "може" бути). Я, мабуть, збираюся використовувати якийсь "гібридний" підхід використання програми для зберігання та завантаження даних, але потім використовую атрибут "android: орієнтація" на активність у файлі маніфесту для зміни нормальної поведінки знищення та відновлення діяльності. Все це, звичайно, передбачає, що додаток може визначити "коли" його знищують, щоб зберегти дані.
Дейв

Відповіді:


134

Я не думаю, що 500 кб буде не такою великою угодою.

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

Ви можете передавати дані в глобальному синглтоні, якщо він буде використовуватися багато.

public class YourApplication extends Application 
{     
     public SomeDataClass data = new SomeDataClass();
}

Потім зателефонуйте йому в будь-яку діяльність:

YourApplication appState = ((YourApplication)this.getApplication());
appState.data.UseAGetterOrSetterHere(); // Do whatever you need to with the data here.

Я обговорюю це у своєму дописі в блозі , в розділі "Глобальний синглтон".


1
На жаль, зазначена публікація в блозі вже не доступна за цією адресою.
mikebabcock

1
Я переміщав речі на своєму сайті. Поки це не виправлено, ви можете знайти його на archive.org тут: web.archive.org/web/20130818035631/http://www.bryandenny.com/…
Брайан Денні

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

1
@ZivKesten Як щодо додавання name = атрибута до тегу програми всередині маніфесту?
MikeC

@mgc дякую, що минув деякий час, і так, я зрештою це розробив, а також створив екземпляри цього класу там, де мені це потрібно, надавши йому getApplicationContext () з анонсом до цього класу
Ziv Kesten

57

Ті, хто розраховує на Applicationекземпляр, помиляються. Спочатку може здатися, що це Applicationіснує до тих пір, поки існує весь додаток, але це неправильне припущення.

ОС може вбивати процеси за необхідності. Усі процеси поділяються на 5 рівнів "вдатливості", зазначених у документі .

Наприклад, якщо ваша програма перебуває у фоновому режимі через відповідь користувача на вхідний дзвінок, то залежно від стану оперативної пам’яті ОС може (або не може) вбити ваш процес (знищивши Applicationекземпляр у процесі) .

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

ОНОВЛЕННЯ:

У мене було багато негативних відгуків, тому пора додати уточнення. :) Ну, спочатку я дійсно використовував неправильне припущення, що стан дійсно важливий для програми. Однак якщо у вашій програмі все гаразд, що іноді стан втрачається (це можуть бути деякі зображення, які будуть просто перечитані / перезавантажені), тоді повністю зберігати його як член Application.


14
Якщо Програма вбита, то кого це хвилює, правда? Додаток зник. Як я розумію, Android відновлює процеси, які містять пам'ять, на зразок діяльності. Якщо процес, що містить додаток, загинув (якщо Android навіть зробить це?), Це по суті як вбивство програми. Користувачеві потрібно буде запустити додаток ще раз, і в цей момент, кого це хвилює? Це новий екземпляр програми.
Андрій

14
Це було для нас незвичайним сюрпризом у виробництві. Повірте, Android вбиває процеси, це просто залежить від стану оперативної пам’яті та інших факторів, описаних у документації. Для нас це був кошмар, тому я просто ділюсь своїм реальним досвідом. Ну, у нас цього не було на емуляторах, але в реальному світі деякі пристрої «перевантажені» додатками, тому вбивство фонового процесу є нормальною ситуацією. Так, якщо користувач вирішить отримати програму на перший план - ОС відновлює його стек, включаючи Applicationекземпляр, однак не буде ваших статичних даних, на які ви розраховуєте, якщо ви не зберегли його.
Віт Худенко

2
Я думаю, що я, мабуть, буду використовувати гібридний підхід. Я вже знав про явний трюк, щоб перемогти зміну орієнтації (що має й інші переваги). Оскільки додаток - це гра, я не впевнений, що наполягання даних між запусками є досить важливим; хоча це, мабуть, не буде дуже важко, оскільки більшість даних можна серіалізувати (хоча я не хотів би серіалізувати та несеріалізувати між кожною зміною орієнтації). Я, безумовно, ціную вклад. Я б не сказав, що ті, що залежать від екземпляра програми, "неправильні". Багато що залежить від програми :).
Дейв

1
@Arhimed Ви занадто багато узагальнюєте свою відповідь. І пропонуючи вузький підхід, заснований на ваших припущеннях. Неправдиве припущення: дані, що містяться в статичних змінних, потрібно зберігати протягом сеансів програми. Можуть бути численні випадки використання, коли дані є тривіальними і їх не потрібно зберігати негайно.
Mandar Limaye

2
У мене є близько 1mb даних зі складною структурою. Серіалізація / десеріалізація може коштувати мені до 2-3 секунд, коли пристрій перевантажений роботою. Ідея економити / завантажувати між видами діяльності коштує занадто багато часу. Я використовую додаток як сховище. Звичайно, мій клас даних, що зберігається в екземплярі програми, перевіряє кожен метод - чи дані ще живі чи потрібно завантажувати. Тож Дейву доводиться: 1. надавати навантаження / збереження фіксації 2. утримувати дані у застосуванні. 3. Потрійна логіка перевірки доступу до даних.
Костадин

6

Якщо ви хочете отримати доступ до "Глобального синглтона" поза діяльністю, і ви не хочете проходити Contextчерез усі залучені об'єкти для отримання синглтона, ви можете просто визначити статичний атрибут у вашому класі додатків, на який посилається себе. Просто ініціалізуйте атрибут у onCreate()методі.

Наприклад:

public class ApplicationController extends Application {
    private static ApplicationController _appCtrl;

    public static ApplicationController getAppCtrl()
    {
         return _appCtrl;
    }
}

Оскільки підкласи Applicationтакож можуть отримати Ресурси, ви можете отримати доступ до них просто, визначивши статичний метод, який повертає їх, наприклад:

public static Resources getAppResources()
{
    return _appCtrl.getResources();
}

Але будьте дуже обережні, обходячи посиланнями контексту, щоб уникнути витоку пам'яті .


6
Ви забули зауважити, що для додавання тегу додатків у ваш маніфест для класу, який слід інстанціювати, потрібно додати андроїд: name = ". ApplicationController".
eggie5

Насправді вам не потрібно продовжувати Applicationце робити. Ви можете оголосити статичну змінну члена в будь-якому класі для цього.
Девід Вассер

2

Дейв, що це за дані? Якщо загальні дані стосуються програми в цілому (приклад: дані користувача), тоді розгорніть клас програми та зберігайте їх там. Якщо дані відносяться до активності, вам слід використовувати обробники onSaveInstanceState і onRestoreInstanceState, щоб зберегти дані при обертанні екрана.


Що робити, якщо дані дійсно великі для зберігання в посилці? Це те, що я отримую: android.os.TransactionTooLargeException: розмір посилки даних 838396 байт
Arjun

1

Ви можете фактично змінити функцію орієнтації, щоб переконатися, що ваша діяльність не знищена та відтворена. Подивіться сюди .


16
Можна багато чого зробити. Це не означає, що вони хороші ідеї. Це не дуже гарна ідея.
Андрій

Тестування, змінивши орієнтацію екрана, - це найпростіший спосіб переконатися, що ваш додаток робить те, що Android передбачає.
18446744073709551615

0

Ви можете створити клас програми та зберегти всі дані на цьому кальсі для використання в будь-якому місці вашої програми.


0

Я знаю, що це дуже старе питання, але використання ViewModel з компонентів jetpack є найкращим способом збереження даних між обертаннями діяльності.

Клас ViewModel призначений для зберігання та управління даними, пов’язаними з інтерфейсом користувача, свідомим способом життєвого циклу. Клас ViewModel дозволяє пережити дані зміни конфігурації, такі як обертання екрана.

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