508

I am using SharedPreferences in my android app. I am using both commit() and apply() method from shared preference. When I use AVD 2.3 it shows no error, but when I run the code in AVD 2.1, apply() method shows error.

So what's the difference between these two? And by using only commit() can I store the preference value without any problem?

Stornu2
  • 2,284
  • 3
  • 27
  • 47
Andro Selva
  • 53,910
  • 52
  • 193
  • 240
  • 132
    This is a year old, but I'm going to comment on it anyway, although it may be obvious, none of the answers make this point: `apply()` will asynchronously do disk I/O while `commit()` is synchronous. So you really shouldn't call `commit()` from the UI thread. – okonomichiyaki Jun 18 '12 at 19:45
  • Of note, when multiple SharedPreferences.Editor objects are in use, the last one to call `apply()` wins. Therefore, you can use `apply()` in lieu of `commit()` safely if you make sure only one SharedPreferences.Editor is being used by your application. – aoeu Apr 28 '17 at 22:48
  • 2
    As per Android Studio Lint warning: commit() will save data immediately and synchronously. However, apply() will save it asynchronously (in the background) and thereby improving some performance. That is why apply() is preferred over commit() if you don't care about its return type (If the data is saved successfully or not). – Rahul Raina Feb 16 '18 at 08:54
  • Is there a way to disable the Lint warning when using `commit()`? – QED Jun 27 '19 at 18:39

9 Answers9

732

apply() was added in 2.3, it commits without returning a boolean indicating success or failure.

commit() returns true if the save works, false otherwise.

apply() was added as the Android dev team noticed that almost no one took notice of the return value, so apply is faster as it is asynchronous.

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

Micer
  • 8,731
  • 3
  • 79
  • 73
Ray Britton
  • 8,257
  • 3
  • 23
  • 32
  • 8
    This answer is true but I guess the @spacemanaki 's comment above is also true contains valuable information – Aksel Fatih Nov 08 '13 at 10:24
  • 70
    commit() writes its data to persistent storage immediately, whereas apply() will handle it in the background. – capt.swag Jan 04 '15 at 06:32
  • 23
    does it create a race condition? – ChrisMcJava Jun 30 '15 at 22:06
  • @ChrisMcJava Does what create a race condition? – Ray Britton Sep 08 '15 at 08:11
  • does apply() create a race condition? because of the asynchronous access to the value in shared prefs – ChrisMcJava Sep 08 '15 at 18:59
  • 1
    @ChrisMcJava the docs state: the last one to call apply wins. – Ray Britton Sep 09 '15 at 07:01
  • 49
    What happens if I write something with apply() and try to read it immediately after? Is the read guaranteed to give me the newest value? The docs say if another commit() happens after you fire apply(), that commit() will block until the apply() is persisted to disk, which makes it clear that this problem does not happen when it comes to 'write' operations, but what about if you are writing and reading immediately after? From my tests, the newest value is returned, but I want to know if this is 100% guaranteed or not. – Bitcoin Cash - ADA enthusiast Sep 20 '15 at 22:44
  • 7
    @Tiago, based on https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/SharedPreferencesImpl.java it looks like apply writes to a map that is later written to disk, and using methods like getInt get the int from that map. – Ray Britton Sep 21 '15 at 13:02
  • 28
    it's safe to replace any instance of commit() with apply() see http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#apply() – Tigran Sarkisian Sep 23 '15 at 07:56
  • 2
    @Tiago I think this part of the documentation will clear your doubt. `Unlike commit(), which writes its preferences out to persistent storage synchronously, apply() commits its changes to the in-memory SharedPreferences immediately but starts an asynchronous commit to disk and you won't be notified of any failures.` – rahulrvp Oct 04 '16 at 06:00
  • 3
    Just for an extra 2 cents... The only time I've seen this as an issue is when an app is 'restarted'. (usually to rebuild the app in a dev environment) The restarted version of the app will have a new instance of shared prefs built off of bad info. – eimmer Oct 12 '16 at 19:46
  • judging by [the source code](https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/SharedPreferencesImpl.java#L535), if there is another disk write in flight, then `commit` will actually queue the commit to run asynchronously (i.e. it will follow the same logic path as `apply` when `mDiskWritesInFlight` is greater than 1) – gMale Dec 01 '16 at 07:09
  • @Tiago Neither commit() nor apply() guarantee to write immediately. I don't know the documentation but I tried many times and it just doesn't work. – Lorenzo Von Matterhorn Dec 30 '16 at 19:28
  • 2
    @BitcoinCash-ADAenthusiast I know it is too late to comment but as per the doc `apply() commits its changes to the in-memory SharedPreferences immediately but starts an asynchronous commit to disk`. So as soon as you commit and try to read, you will get the latest value from in-memory SharedPreferences. – kartik srivastava Jun 10 '21 at 18:19
271

tl;dr:

  • commit() writes the data synchronously (blocking the thread its called from). It then informs you about the success of the operation.
  • apply() schedules the data to be written asynchronously. It does not inform you about the success of the operation.
  • If you save with apply() and immediately read via any getX-method, the new value will be returned!
  • If you called apply() at some point and it's still executing, any calls to commit() will block until all past apply-calls and the current commit-call are finished.

More in-depth information from the SharedPreferences.Editor Documentation:

Unlike commit(), which writes its preferences out to persistent storage synchronously, apply() commits its changes to the in-memory SharedPreferences immediately but starts an asynchronous commit to disk and you won't be notified of any failures. If another editor on this SharedPreferences does a regular commit() while a apply() is still outstanding, the commit() will block until all async commits are completed as well as the commit itself.

As SharedPreferences instances are singletons within a process, it's safe to replace any instance of commit() with apply() if you were already ignoring the return value.

The SharedPreferences.Editor interface isn't expected to be implemented directly. However, if you previously did implement it and are now getting errors about missing apply(), you can simply call commit() from apply().

Lukas Knuth
  • 25,449
  • 15
  • 83
  • 111
  • 24
    This is a much better answer since it mentions that `apply()` is asynchronous and pending writes block future calls to `commit()`. – spaaarky21 Oct 28 '15 at 17:18
26

I'm experiencing some problems using apply() instead commit(). As stated before in other responses, the apply() is asynchronous. I'm getting the problem that the changes formed to a "string set" preference are never written to the persistent memory.

It happens if you "force detention" of the program or, in the ROM that I have installed on my device with Android 4.1, when the process is killed by the system due to memory necessities.

I recommend to use "commit()" instead "apply()" if you want your preferences alive.

JoseLSegura
  • 3,830
  • 3
  • 20
  • 27
  • Are you sure your problem is not related due to concurrent threading? After you send apply(), you have to wait a while to read the things you added, otherwise the UI thread will attempt to read before the worker thread of apply() commited the changes. – Marco Altran Aug 21 '14 at 05:11
  • Regarding string set, http://stackoverflow.com/questions/16820252/android-string-set-preference-is-not-persistent – J.G.Sebring Aug 20 '15 at 09:34
  • @JoseLSegura - the docs suggest otherwise: http://developer.android.com/intl/ja/reference/android/content/SharedPreferences.Editor.html#apply() "You don't need to worry about Android component lifecycles and their interaction with apply() writing to disk. The framework makes sure in-flight disk writes from apply() complete before switching states." I'm wondering if what you are seeing is a bug in Android, and if so whether it has been fixed in newer versions. – ToolmakerSteve Sep 19 '15 at 11:59
  • The very same problem washappening to me using the library "ProcessPhoenix" to reset my app. I was saving a preference just before performing a reset, and "apply" was not working. – ElYeante May 05 '19 at 22:31
15

Use apply().

It writes the changes to the RAM immediately and waits and writes it to the internal storage(the actual preference file) after. Commit writes the changes synchronously and directly to the file.

Mustafa
  • 1,738
  • 2
  • 24
  • 34
15
  • commit() is synchronously, apply() is asynchronous

  • apply() is void function.

  • commit() returns true if the new values were successfully written to persistent storage.

  • apply() guarantees complete before switching states , you don't need to worry about Android component lifecycles

If you dont use value returned from commit() and you're using commit() from main thread, use apply() instead of commit()

Nurlan Sofiyev
  • 499
  • 6
  • 8
13

The docs give a pretty good explanation of the difference between apply() and commit():

Unlike commit(), which writes its preferences out to persistent storage synchronously, apply() commits its changes to the in-memory SharedPreferences immediately but starts an asynchronous commit to disk and you won't be notified of any failures. If another editor on this SharedPreferences does a regular commit() while a apply() is still outstanding, the commit() will block until all async commits are completed as well as the commit itself. As SharedPreferences instances are singletons within a process, it's safe to replace any instance of commit() with apply() if you were already ignoring the return value.

Dan Getz
  • 8,774
  • 6
  • 30
  • 64
Mojo Risin
  • 8,136
  • 5
  • 45
  • 58
11

The difference between commit() and apply()

We might be confused by those two terms, when we are using SharedPreference. Basically they are probably the same, so let’s clarify the differences of commit() and apply().

1.Return value:

apply() commits without returning a boolean indicating success or failure. commit() returns true if the save works, false otherwise.

  1. Speed:

apply() is faster. commit() is slower.

  1. Asynchronous v.s. Synchronous:

apply(): Asynchronous commit(): Synchronous

  1. Atomic:

apply(): atomic commit(): atomic

  1. Error notification:

apply(): No commit(): Yes

Chanaka Weerasinghe
  • 5,404
  • 2
  • 26
  • 39
  • 1
    How is `apply()` "faster" than `commit()`? They essentially represent a same task that would be put in Looper of the thread. `commit()` puts that task in the main Looper while `apply()` takes it on the background, thereby keeping the main looper free of disk I/O task. – Taseer Sep 25 '19 at 16:31
  • 1
    Unlike commit(), which writes its preferences out to persistent storage synchronously, apply() commits its changes to the in-memory SharedPreferences immediately but starts an asynchronous commit to disk and you won't be notified of any failures. If another editor on this SharedPreferences does a regular commit() while a apply() is still outstanding, the commit() will block until all async commits are completed as well as the commit itself see the DOC https://developer.android.com/reference/android/content/SharedPreferences.Editor#apply() – Chanaka Weerasinghe Sep 26 '19 at 03:53
7

From javadoc:

Unlike commit(), which writes its preferences out to persistent storage synchronously, apply() commits its changes to the in-memory SharedPreferences immediately but starts an asynchronous commit to disk and you won't be notified of any failures. If another editor on this SharedPreferences does a regular commit() while a > apply() is still outstanding, the commit() will block until all async commits are completed as well as the commit itself

Vladimir Ivanov
  • 42,730
  • 18
  • 77
  • 103
0

While working with a web API I noticed the main shortcomings for apply() when using shared preferences before logging out.

Behold the following scenario: User logs in and token (for automatic relogging) was passed with the POST.

SharedPreferences preferences = App.getContext().getSharedPreferences("UserCredentials", Context.MODE_PRIVATE);

SharedPreferences.Editor editor = preferences.edit();

editor.putString("TOKEN",token);

editor.apply();

Token is available throughout all sessions, no problem and automatic relogging is done without any further problems throughout the states.

While writing the logout function I cleared the shared preferences as follows

SharedPreferences preferences = App.getContext().getSharedPreferences("UserCredentials", Context.MODE_PRIVATE);

SharedPreferences.Editor editor = preferences.edit();

editor.clear();

editor.apply()

In short you could simply write as:

preferences.edit().clear().apply()

To make sure I cleared the cache I would Log before logging out, and preferences.getString("TOKEN"); showed as null.

After restarting the main activity (as it started with a login fragment) - I would check the token again, using:

SharedPreferences preferences = App.getContext().getSharedPreferences("UserCredentials", MODE_PRIVATE);
        
String retrievedToken = preferences.getString("TOKEN",null); // Second param = default value

Log.d(TAG, "RETRIEVING TOKEN: " + retrievedToken);

The token actually re-appeared, even though the token was most certainly cleared before logging out.

(Causing a logout -> 'login-using-token loop)

Only after adding editor.commit(); to both setting and clearing the token would actually be permanently gone.

Do note, I used an emulator.

This behavior actually makes sence, as the in-memory storage is updated but the async call never made it before the app was restarted.

Therefor commit(); would FORCE the app to wait (synchronously) with actual subsequent commands like system.exit() etcetera, while apply() could very well fail if other commands would force a certain state change in the app.

To make sure you hit all the right spots, you can always use apply() & commit() both subsequently.