В чем разница между commit () и apply () в SharedPreferences

431

Я использую SharedPreferencesв моем приложении для Android. Я использую оба commit()и apply()метод из общих предпочтений. Когда я использую AVD 2.3, это не показывает ошибку, но когда я запускаю код в AVD 2.1, apply()метод показывает ошибку.

Так в чем же разница между этими двумя? И с помощью только commit()я могу сохранить значение предпочтения без каких-либо проблем?

Андро Сельва
источник
115
Это год, но я все равно прокомментирую его, хотя это может быть очевидно, но ни один из ответов не говорит об этом: apply()будет асинхронно выполнять дисковый ввод-вывод, пока commit()он синхронный. Так что вам действительно не следует звонить commit()из потока пользовательского интерфейса.
michiakig
Следует отметить, что при использовании нескольких объектов SharedPreferences.Editor apply()побеждает последний из вызываемых объектов . Таким образом, вы можете использовать apply()вместо commit()безопасного, если вы уверены, что только одно SharedPreferences.Editor используется вашим приложением.
17
2
Согласно предупреждению Android Studio Lint: commit () сохранит данные немедленно и синхронно. Однако apply () сохранит его асинхронно (в фоновом режиме) и тем самым улучшит некоторую производительность. Вот почему apply () предпочтительнее, чем commit (), если вы не заботитесь о его типе возврата (если данные успешно сохранены или нет).
Рахул Райна
Есть ли способ отключить предупреждение Lint при использовании commit()?
QED

Ответы:

653

apply()был добавлен в 2.3, он фиксирует без возврата логического значения, указывающего на успех или неудачу.

commit()возвращает true, если сохранение работает, иначе false .

apply() была добавлена, так как команда разработчиков Android заметила, что почти никто не обратил внимания на возвращаемое значение, поэтому применять быстрее, поскольку оно асинхронно.

http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#apply ()

Рэй Бриттон
источник
8
Этот ответ верен, но я думаю, что приведенный выше комментарий @spacemanaki также верен и содержит ценную информацию
Аксель Фатих
58
commit () записывает свои данные в постоянное хранилище немедленно, тогда как apply () будет обрабатывать их в фоновом режиме.
capt.swag
18
это создает условия гонки?
ChrisMcJava
42
Что произойдет, если я напишу что-нибудь с apply () и попытаюсь прочитать это сразу после? Гарантированное чтение даст мне новейшую ценность? В документах говорится, что если после выполнения apply () произойдет другой commit (), то commit () будет блокироваться до тех пор, пока apply () не будет сохранена на диске, что дает понять, что эта проблема не возникает, когда дело доходит до операций write а что если вы пишете и читаете сразу после? Из моих тестов возвращается самое новое значение, но я хочу знать, гарантировано ли это на 100% или нет.
Тиаго
22
можно безопасно заменить любой экземпляр commit () на apply (), см. developer.android.com/reference/android/content/…
Тигран Саркисян,
221

ТЛ; др:

  • commit()записывает данные синхронно (блокируя поток, из которого они вызваны). Затем он информирует вас об успехе операции.
  • apply()планирует данные для записи асинхронно . Он не информирует вас об успешности операции.
  • Если вы сохраните apply()и сразу прочитаете с помощью любого метода getX, новое значение будет возвращено!
  • Если вы позвонили apply()в какой-то момент и он все еще выполняется, любые вызовы commit()блокируются до тех пор, пока не завершатся все прошлые вызовы apply и текущий commit-вызов.

Более подробная информация из документации SharedPreferences.Editor :

В отличие от commit (), который синхронно записывает свои предпочтения в постоянное хранилище , apply () немедленно фиксирует свои изменения в SharedPreferences в памяти, но запускает асинхронную фиксацию на диск, и вы не будете уведомлены о каких-либо сбоях . Если другой редактор в этой SharedPreferences выполняет обычную commit (), а apply () еще не выполнено, commit () будет блокироваться до тех пор, пока не будут выполнены все асинхронные коммиты, а также сам коммит.

Поскольку экземпляры SharedPreferences являются одиночными внутри процесса, любой экземпляр commit () можно безопасно заменить на apply (), если вы уже игнорировали возвращаемое значение.

Ожидается, что интерфейс SharedPreferences.Editor не будет реализован напрямую. Однако, если вы ранее реализовали это и теперь получаете ошибки об отсутствии apply (), вы можете просто вызвать commit () из apply ().

Лукас Кнут
источник
19
Это гораздо лучший ответ, поскольку в нем упоминается, что apply()он асинхронный, и ожидающие записи блокируют будущие вызовы commit().
spaaarky21
22

У меня возникают некоторые проблемы с использованием apply () вместо commit (). Как указано ранее в других ответах, apply () является асинхронным. Я получаю проблему, что изменения, сформированные в предпочтении "набора строк", никогда не записываются в постоянную память.

Это происходит, если вы «принудительно задерживаете» программу или в ПЗУ, которое я установил на моем устройстве с Android 4.1, когда процесс прерывается системой из-за необходимости в памяти.

Я рекомендую использовать «commit ()» вместо «apply ()», если вы хотите, чтобы ваши настройки были активными.

JoseLSegura
источник
Вы уверены, что ваша проблема не связана с параллельным потоком? После отправки apply () вам придется подождать некоторое время, чтобы прочитать добавленные вами вещи, иначе поток пользовательского интерфейса попытается прочитать, прежде чем рабочий поток apply () подтвердит изменения.
Марко Альтран
Что касается набора строк, stackoverflow.com/questions/16820252/…
Tapirboy
@JoseLSegura - документы предлагают иное: developer.android.com/intl/ja/reference/android/content/… "Вам не нужно беспокоиться о жизненных циклах компонентов Android и их взаимодействии с apply (), записывающим на диск. гарантирует, что запись на диск во время выполнения команды apply () завершится до переключения состояний. " Мне интересно, является ли то, что вы видите, ошибкой в ​​Android, и если да, то была ли она исправлена ​​в более новых версиях.
ToolmakerSteve
Та же самая проблема возникла со мной при использовании библиотеки «ProcessPhoenix» для сброса моего приложения. Я сохранял настройки перед выполнением сброса, и «применить» не работало.
ElYeante
14

Используйте apply ().

Он немедленно записывает изменения в ОЗУ, а затем ожидает и записывает их во внутреннее хранилище (файл фактических настроек). Коммит записывает изменения синхронно и напрямую в файл.

Мустафа
источник
14
  • commit()синхронно, apply()асинхронно

  • apply() является пустой функцией.

  • commit() возвращает true, если новые значения были успешно записаны в постоянное хранилище.

  • apply() перед переключением состояний гарантия завершена, вам не нужно беспокоиться о жизненных циклах компонентов Android

Если вы не используете значение, возвращаемое из, commit()и используете commit()из основного потока, используйте apply()вместо commit()

Нурлан Софиев
источник
13

Документы дают довольно хорошее объяснение разницы между apply()и commit():

В отличие от этого commit(), который записывает свои предпочтения в постоянное хранилище синхронно, немедленно apply()фиксирует свои изменения в оперативной памяти, SharedPreferencesно запускает асинхронную фиксацию на диск, и вы не будете уведомлены о каких-либо сбоях. Если другой редактор SharedPreferencesделает это регулярно, в commit()то время как a apply()все еще не выполнено, он commit()будет блокироваться до тех пор, пока не будут выполнены все асинхронные коммиты, а также сам коммит. Как SharedPreferencesэкземпляры одноэлементны внутри процесса, это безопасно заменить любой экземпляр commit()с , apply()если вы уже не обращая внимания на возвращаемое значение.

Моджо Рисин
источник
6

Из Javadoc:

В отличие от commit (), который синхронно записывает свои предпочтения в постоянное хранилище, apply () немедленно фиксирует свои изменения в SharedPreferences в памяти, но запускает асинхронную фиксацию на диск, и вы не будете уведомлены о каких-либо сбоях. Если другой редактор в этой SharedPreferences выполняет обычную commit (), в то время как a> apply () все еще не завершен, commit () будет блокироваться до тех пор, пока не будут выполнены все асинхронные коммиты, а также сам коммит

Владимир Иванов
источник
1

Разница между commit () и apply ()

Мы можем быть смущены этими двумя терминами, когда мы используем SharedPreference. В основном они, вероятно, одинаковы, поэтому давайте выясним различия в commit () и apply ().

1. Возврат стоимости:

apply()фиксирует без возврата логического значения, указывающего на успех или неудачу. commit() возвращает true, если сохранение работает, иначе false.

  1. Скорость:

apply()быстрее. commit()медленнее.

  1. Асинхронный против Синхронного:

apply(): Асинхронный commit(): синхронный

  1. Atomic:

apply(): атомная commit(): атомная

  1. Уведомление об ошибке:

apply(): Нет commit(): да

Чанака Вирасингхе
источник
Как это apply()"быстрее", чем commit()? По сути, они представляют собой ту же задачу, которая будет поставлена ​​в Looper потока. commit()помещает эту задачу в основной Looper, а apply()в фоновом режиме, тем самым освобождая главный петлитель от задачи дискового ввода-вывода.
Тасиир
В отличие от commit (), который синхронно записывает свои предпочтения в постоянное хранилище, apply () немедленно фиксирует свои изменения в SharedPreferences в памяти, но запускает асинхронную фиксацию на диск, и вы не будете уведомлены о каких-либо сбоях. Если другой редактор в этой SharedPreferences выполняет обычную commit (), а apply () еще не выполнено, commit () будет блокироваться до тех пор, пока не будут выполнены все асинхронные коммиты, а также сам коммит, см. DOC developer.android.com/reference/ android / content /…
Чанака Вирасингхе