Should accessing SharedPreferences be done off the UI Thread?
I'm glad you're already playing with it!
Some things to note: (in lazy bullet form)
- if this is the worst of your problems, your app's probably in a good spot. :) Writes are generally slower than reads, though, so be sure you're using SharedPreferenced$Editor.apply() instead of commit(). apply() is new in GB and async (but always safe, careful of lifecycle transitions). You can use reflection to conditionally call apply() on GB+ and commit() on Froyo or below. I'll be doing a blogpost with sample code of how to do this.
Regarding loading, though...
once loaded, SharedPreferences are singletons and cached process-wide. so you want to get it loaded as early as possible so you have it in memory before you need it. (assuming it's small, as it should be if you're using SharedPreferences, a simple XML file...) You don't want to fault it in the future time some user clicks a button.
but whenever you call context.getSharedPreferences(...), the backing XML file is stat'd to see if it's changed, so you'll want to avoid those stats during UI events anyway. A stat should normally be fast (and often cached), but yaffs doesn't have much in the way of concurrency (and a lot of Android devices run on yaffs... Droid, Nexus One, etc.) so if you avoid disk, you avoid getting stuck behind other in-flight or pending disk operations.
so you'll probably want to load the SharedPreferences during your onCreate() and re-use the same instance, avoiding the stat.
but if you don't need your preferences anyway during onCreate(), that loading time is stalling your app's start-up unnecessarily, so it's generally better to have something like a FutureTask<SharedPreferences> subclass that kicks off a new thread to .set() the FutureTask subclasses's value. Then just lookup your FutureTask<SharedPreferences>'s member whenever you need it and .get() it. I plan to make this free behind the scenes in Honeycomb, transparently. I'll try to release some sample code which
shows best practices in this area.
Check the Android Developers blog for upcoming posts on StrictMode-related subjects in the coming week(s).
Can and Should we commit SharedPreferences on NON UI thread, if yes how ?
so is there a way to save and retrieve data on NON-UI thread.
SharedPreferences
are cached. The first time you try accessing a given SharedPreferences
(e.g., getSharedPreferences()
), there will be disk I/O. You are welcome to do this work on a background thread, sometime in advance of when you need the preferences.
You can call apply()
, rather than commit()
, to persist changes to the SharedPreferences
on a framework-supplied background thread.
Accessing SharedPreferences On Separate Thread
Is editing shared preferences in a separate thread redundant if you use apply?
Yes, but bear in mind that you may not only be editing SharedPreferences
. You may be reading them as well.
Given the nature of your code, my guess is that you're calling it as one of the first things in your LAUNCHER
activity. If so, nothing else will have retrieved those SharedPreferences
yet, and so you will get disk-read violations from StrictMode
for the reading, not so much the editing.
Since you already have the background thread, I'd switch to commit()
rather than use apply()
and waste another thread.
SharedPreferences and Thread Safety
Processes and Threads are different. The SharedPreferences implementation in Android is thread-safe but not process-safe. Normally your app will run all in the same process, but it's possible for you to configure it in the AndroidManifest.xml so, say, the service runs in a separate process than, say, the activity.
To verify the thready safety, see the ContextImpl.java's SharedPreferenceImpl from AOSP. Note there's a synchronized wherever you'd expect there to be one.
private static final class SharedPreferencesImpl implements SharedPreferences {
...
public String getString(String key, String defValue) {
synchronized (this) {
String v = (String)mMap.get(key);
return v != null ? v : defValue;
}
}
...
public final class EditorImpl implements Editor {
public Editor putString(String key, String value) {
synchronized (this) {
mModified.put(key, value);
return this;
}
}
...
}
}
However for your case of the unique id it seems you'd still want a synchronized as you don't want it to change between the get and the put.
Trying to establish best practices for SharedPreferences
public boolean getPrefs()
{
prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
PREF1 = prefs.getBoolean("pref1_key",pref1_default);
PREF2 = prefs.getString("pref2_key","pref2_default");
}
use this method to get all preferences you need. Call this in the onResume() or onCreate() method. You needn't worry about UI or anything
Android SharedPreferences Best Practices
If you have a large application that is relying on SharedPreferences you could have key duplication, especially in the case of using some third party library that relies on SharedPreferences as well.
Libraries should not use that particular SharedPreferences
. The default SharedPreferences
should only be used by the application.
This way if you have a class that heavily relies on SharedPreferences you can create a preference file that is used only by your class.
You are certainly welcome to do this. I wouldn't, at the application level, as the primary reason for SharedPreferences
is to have them be shared among the components in the application. A development team should have no problem managing this namespace, just as they should have no problem managing names of classes, packages, resources, or other project-level stuff. Moreover, the default SharedPreferences
are what your PreferenceActivity
will use.
However, going back to your libraries point, reusable libraries should use a separate SharedPreferences
for their library only. I would not base it on a class name, because then you are one refactoring away from breaking your app. Instead, pick a name that is unique (e.g., based on the library name, such as "com.commonsware.cwac.wakeful.WakefulIntentService"
) but stable.
it seems that accesses SharedPreferences should be done off the UI thread which makes sense.
Ideally, yes. I recently released a SharedPreferencesLoader
that helps with this.
Are there any other best practices Android developers should be aware of when using SharedPreferences in their applications?
Don't over-rely upon them. They are stored in XML files and are not transactional. A database should be your primary data store, particularly for data you really don't want to lose.
Can I access shared preferences (save/edit) from Main Thread?
It's pretty light. If there's any doubt, you can use SharedPreferences.Editor#apply()
which writes to disk asynchronously instead of commit()
which writes synchronously.
Related Topics
Wallpaper Not Properly Fit on Device Screen
Opencv Android Green Color Detection
How to Display Fetched JSON Data into Listview Using Baseadapter
Why Can't One Add/Remove Items from an Arrayadapter
Android Studio Where to Install Ndk File? (Downloaded It in Zip)
How to Raise a Toast in Asynctask, I am Prompted to Used the Looper
App Getting Stuck with E/Com.Facebook.Internal.Attributionidentifiers
Android M Fingerprintmanager.Ishardwaredetected() Returns False on a Samsung Galaxy S5
How Are Android Activities Handled with Jetpack Compose and Compose Navigation
Converting Preview Frame to Bitmap
How to Use Sharedpreferences to Save More Than One Values
How to Call One Android Application from Another Android Application
Cannot Call Getsupportfragmentmanager() from Activity
Android: Skimagedecoder:: Factory Returned Null
Elevation on Android Lollipop Not Working