Jaka jest różnica między commit () a apply () w SharedPreferences

431

Używam SharedPreferencesw mojej aplikacji na Androida. Korzystam zarówno z metody, jak commit()i apply()ze wspólnych preferencji. Kiedy używam AVD 2.3, nie pokazuje błędu, ale kiedy uruchamiam kod w AVD 2.1, apply()metoda pokazuje błąd.

Jaka jest różnica między tymi dwoma? A używając tylko commit()mogę zapisać wartość preferencji bez żadnego problemu?

Andro Selva
źródło
115
To jest rok, ale i tak skomentuję, choć może to być oczywiste, żadna z odpowiedzi nie wskazuje na to: apply()asynchronicznie wykona operacje we / wy dysku, gdy commit()jest synchroniczny. Więc naprawdę nie powinieneś dzwonić commit()z wątku interfejsu użytkownika.
michiakig
Należy zauważyć, że gdy używanych jest wiele obiektów SharedPreferences.Editor, ostatni, który wywołuje, apply()wygrywa. Dlatego możesz używać apply()zamiast commit()bezpiecznie, jeśli upewnisz się, że aplikacja używa tylko jednego programu Preferencje wspólne.
aoeu 28.04.17
2
Zgodnie z ostrzeżeniem Lint systemu Android Studio: commit () zapisze dane natychmiast i synchronicznie. Jednak Apply () zapisze go asynchronicznie (w tle) i tym samym poprawi wydajność. Właśnie dlatego preferowana jest metoda Apply (), a nie commit (), jeśli nie zależy Ci na jej typie zwrotu (jeśli dane zostały zapisane, czy nie).
Rahul Raina
Czy istnieje sposób wyłączenia ostrzeżenia Lint podczas używania commit()?
QED

Odpowiedzi:

653

apply()został dodany w 2.3, zatwierdza bez zwracania wartości logicznej wskazującej na sukces lub porażkę.

commit()zwraca true, jeśli zapisywanie działa, w przeciwnym razie false .

apply() został dodany, gdy zespół programistów Androida zauważył, że prawie nikt nie zwrócił uwagi na wartość zwracaną, więc zastosowanie jest szybsze, ponieważ jest asynchroniczne.

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

Ray Britton
źródło
8
Ta odpowiedź jest prawdziwa, ale sądzę, że powyższy komentarz @spacemanaki również jest prawdziwy, zawiera cenne informacje
Aksel Fatih
58
commit () natychmiast zapisuje swoje dane w pamięci trwałej, podczas gdy appl () obsłuży je w tle.
capt.swag
18
czy to stwarza warunki do wyścigu?
ChrisMcJava
42
Co się stanie, jeśli napiszę coś za pomocą Apply () i spróbuję przeczytać to natychmiast po tym? Czy odczyt ma gwarantowaną najnowszą wartość? Dokumenty mówią, że jeśli po zatwierdzeniu polecenia Apply () nastąpi kolejne zatwierdzenie (), to zatwierdzenie () będzie blokowane do momentu utrwalenia zastosowania () na dysku, co wyjaśnia, że ​​ten problem nie występuje, jeśli chodzi o operacje „zapisu” , ale co jeśli piszesz i czytasz od razu? Z moich testów zwracana jest najnowsza wartość, ale chcę wiedzieć, czy jest to w 100% gwarantowane, czy nie.
Tiago,
22
bezpieczne jest zastąpienie dowolnego wystąpienia commit () przez apply () patrz developer.android.com/reference/android/content/…
Tigran Sarkisian
221

tl; dr:

  • commit()zapisuje dane synchronicznie (blokując wątek, z którego jest wywoływany). Następnie informuje cię o powodzeniu operacji.
  • apply()planuje zapis danych asynchronicznie . Nie informuje Cię o powodzeniu operacji.
  • Jeśli zapiszesz za pomocą dowolnej metody getX apply()i natychmiast ją przeczytasz , nowa wartość zostanie zwrócona!
  • Jeśli apply()w pewnym momencie zadzwoniłeś i nadal się wykonuje, wszystkie wywołania do commit()będą blokowane do czasu zakończenia wszystkich poprzednich wywołań aplikacji i bieżącego zatwierdzenia.

Więcej szczegółowych informacji z SharedPreferences.Editor Documentation:

W przeciwieństwie do commit (), który synchronicznie zapisuje swoje preferencje w trwałym magazynie , Apply () natychmiast zatwierdza zmiany w SharedPreferences w pamięci, ale uruchamia asynchroniczne zatwierdzanie na dysku i nie zostaniesz powiadomiony o żadnych awariach . Jeśli inny edytor w tej opcji SharedPreferences wykonuje zwykłe zatwierdzenie (), podczas gdy Apply () jest nadal zaległe, zatwierdzenie () będzie blokować do momentu zakończenia wszystkich zatwierdzeń asynchronicznych, a także samego zatwierdzenia.

Ponieważ instancje SharedPreferences są singletonami w procesie, można bezpiecznie zastąpić dowolną instancję commit () parametrem apply (), jeśli już ignorowano zwracaną wartość.

Interfejs SharedPreferences.Editor nie powinien zostać zaimplementowany bezpośrednio. Jeśli jednak wcześniej go zaimplementowałeś i teraz pojawiają się błędy związane z brakującym zastosowaniem Apply (), możesz po prostu wywołać commit () z Apply ().

Lukas Knuth
źródło
19
Jest to znacznie lepsza odpowiedź, ponieważ wspomina, że apply()jest asynchroniczna, a oczekujące zapisy blokują przyszłe połączenia commit().
spaaarky21,
22

Występują problemy z użyciem Apply () zamiast commit (). Jak stwierdzono wcześniej w innych odpowiedziach, Apply () jest asynchroniczna. Mam problem z tym, że zmiany utworzone w preferencjach „zestawu ciągów” nigdy nie są zapisywane w pamięci trwałej.

Dzieje się tak, gdy „wymusisz zatrzymanie” programu lub w pamięci ROM zainstalowanej na moim urządzeniu z Androidem 4.1, gdy proces zostanie zabity przez system z powodu konieczności pamięci.

Polecam użyć „commit ()” zamiast „Apply ()”, jeśli chcesz, aby twoje preferencje były żywe.

JoseLSegura
źródło
Czy jesteś pewien, że Twój problem nie jest powiązany z powodu jednoczesnego wątkowania? Po wysłaniu metody Apply () musisz chwilę poczekać, aby przeczytać dodane elementy, w przeciwnym razie wątek interfejsu użytkownika spróbuje odczytać, zanim wątek roboczy metody apply () zatwierdzi zmiany.
Marco Altran,
Jeśli chodzi o zestaw strun, stackoverflow.com/questions/16820252/...
Tapirboy
@JoseLSegura - doktorzy sugerują inaczej: developer.android.com/intl/ja/reference/android/content/… „Nie musisz się martwić cyklami życia komponentów Androida i ich interakcją z zapisem Apply () na dysku. upewnia się, że zapisywanie z dysku podczas lotu z apply () zostało zakończone przed przełączeniem stanów. " Zastanawiam się, czy to, co widzisz, jest błędem w Androidzie, a jeśli tak, to czy zostało to naprawione w nowszych wersjach.
ToolmakerSteve,
Ten sam problem pojawia się przy użyciu biblioteki „ProcessPhoenix”, aby zresetować moją aplikację. Zapisałem preferencję tuż przed zresetowaniem, a funkcja „Zastosuj” nie działała.
ElYeante
14

Użyj Apply ().

Natychmiast zapisuje zmiany w pamięci RAM, a następnie czeka i zapisuje je w pamięci wewnętrznej (plik preferencji). Zatwierdź zapisuje zmiany synchronicznie i bezpośrednio do pliku.

Mustafa
źródło
14
  • commit()jest synchroniczny, apply()jest asynchroniczny

  • apply() jest nieważna.

  • commit() zwraca true, jeśli nowe wartości zostały pomyślnie zapisane w pamięci trwałej.

  • apply() gwarantuje ukończenie przed przełączeniem stanów, nie musisz się martwić cyklami życia komponentów Androida

Jeśli nie używasz wartości zwróconej z commit()i używasz commit()z głównego wątku, użyj apply()zamiast commit()

Nurlan Sofiyev
źródło
13

Docs dają dość dobre wyjaśnienie różnicy między apply()i commit():

W przeciwieństwie do tego commit(), który zapisuje preferencje synchronicznie w pamięci trwałej, natychmiast apply()zatwierdza zmiany w pamięci, SharedPreferencesale uruchamia asynchroniczne zatwierdzanie na dysku i nie zostaniesz powiadomiony o żadnych awariach. Jeśli inny edytor SharedPreferencesrobi to regularnie, commit()dopóki a apply()jest nadal zaległe, commit()blokuje się, dopóki wszystkie zatwierdzenia asynchroniczne nie zostaną zakończone, a także samo zatwierdzenie. Jako SharedPreferencesprzypadki są samotnymi w procesie, to jest bezpieczne, aby zastąpić dowolny wystąpienie commit()z apply()jakbyś już ignorując zwracanej wartości.

Mojo Risin
źródło
6

Z javadoc:

W przeciwieństwie do commit (), który synchronicznie zapisuje swoje preferencje w trwałym magazynie, Apply () natychmiast zatwierdza zmiany w SharedPreferences w pamięci, ale uruchamia asynchroniczne zatwierdzanie na dysku i nie zostaniesz powiadomiony o żadnych awariach. Jeśli inny edytor w tym SharedPreferences wykonuje zwykłe zatwierdzenie (), podczas gdy> Apply () jest nadal zaległe, zatwierdzenie () będzie blokować do momentu zakończenia wszystkich zatwierdzeń asynchronicznych, a także samego zatwierdzenia

Vladimir Ivanov
źródło
1

Różnica między zatwierdzeniem () a zastosowaniem ()

Te dwa warunki mogą nas mylić, gdy korzystamy z SharedPreference. Zasadniczo są one prawdopodobnie takie same, więc wyjaśnijmy różnice między commit () a apply ().

1. wartość Zwrotu:

apply()zatwierdza bez zwracania wartości logicznej wskazującej powodzenie lub niepowodzenie. commit() zwraca true, jeśli zapisywanie działa, w przeciwnym razie false.

  1. Prędkość:

apply()jest szybszy. commit()jest wolniejszy.

  1. Asynchroniczny vs Synchroniczny:

apply(): Asynchroniczny commit(): Synchroniczny

  1. Atomowy:

apply(): atomowy commit(): atomowy

  1. Powiadomienie o błędzie:

apply(): Nie commit(): Tak

Chanaka Weerasinghe
źródło
Jak to jest apply()„szybsze” niż commit()? Zasadniczo reprezentują one to samo zadanie, które zostanie umieszczone w Looper wątku. commit()umieszcza to zadanie w głównym Looper, podczas gdy apply()przenosi je w tle, dzięki czemu główny looper jest wolny od zadania We / Wy dysku.
Taseer
W przeciwieństwie do commit (), który synchronicznie zapisuje swoje preferencje w trwałym magazynie, Apply () natychmiast zatwierdza zmiany w SharedPreferences w pamięci, ale uruchamia asynchroniczne zatwierdzanie na dysku i nie zostaniesz powiadomiony o żadnych awariach. Jeśli inny edytor w tym SharedPreferences wykonuje zwykłe zatwierdzenie (), podczas gdy Apply () jest nadal zaległe, zatwierdzenie () będzie blokowało się, dopóki wszystkie zatwierdzenia asynchroniczne nie zostaną zakończone, a samo zatwierdzenie wyświetli DOC developer.android.com/reference/ android / content /…
Chanaka Weerasinghe