Not getting value from Shared Preferences instantly - android

I am storing the data in the Shared Preferences by
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("menu_bar","abcd");
editor.apply();
and I am fetching the data from Shared Preferences in fragment by
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(getActivity());
String name = preferences.getString("menu_bar","");
if(!name.equalsIgnoreCase("")){
Toast.makeText(getActivity(), name, Toast.LENGTH_SHORT).show();
It is working when the app is removed from the stack.
But on the first time it is not working. Getting NULL in the first time but working fine from the second time. I also tried with editor.commit() when saving it.

Use getSharedPreferences("MyPref", Context.MODE_PRIVATE) and then commit to reflect changes instantly
SharedPreferences preferences = getSharedPreferences("MyPref", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = preferences.edit();
editor.putString("menu_bar","abcd");
editor.commit();
Official Documentation
Commit your preferences changes back from this Editor to the SharedPreferences object it is editing. This atomically performs the requested modifications, replacing whatever is currently in the SharedPreferences.
Note that when two editors are modifying preferences at the same time, the last one to call apply wins.
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.
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.
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().

Try using the same instance of SharedPreferences. Easiest would be an explicitly named one:
class MyActivity {
private static final String PREFS_NAME = "myActivityPrefs";
private static SharedPreferences sharedPrefs = null;
public static SharedPreferences prefs(Context context) {
if (sharedPrefs == null) {
sharedPrefs = context.getSharedPreferences(PREFS_NAME, 0);
}
return sharedPrefs;
}
}
You then use it in the activity like this:
prefs(this).edit().putString("menu_bar","abcd").apply()
And in the fragment:
String name = MyActivity.prefs(getActivity()).getString("menu_bar","");
This is a recommended mode of operation that would give you good performance without waiting for I/O on your main thread - apply() does that for you but requires using the same instance to be consistent.
To use separate instances (sometimes you're forced to - for example through separate processes) always use commit(), which can freeze your main thread at times, and still doesn't guarantee consistency due to how filesystems work, I've seen instances where commit()ed data wasn't immediately available to a separate process, often on specific devices that had a FS configuration quirk.

Related

Can a SharedPreferences.Editor be reused?

Can a SharedPreferences.Editor be safely reused? In other words, can I have this declared once in my class:
val editor = prefs.edit()
and then use its apply() method multiple times, like this?
editor.putString("myString", "Some string").apply()
// some time later...
editor.putInt("myInt", 682).apply()
Yes you can reuse it and then use its apply() method multiple times to save the values.
I see that you are using Kotlin, is the same as in Java/Android SDK.

Use SharedPreferences on multi-process mode

I've defined an instance of SharedPreferences that used on multi-process mode.
public class Prefs {
private static SharedPreferences prefs;
private static SharedPreferences.Editor editor;
private static void init(Context context) {
prefs = context.getSharedPreferences("alaki",
Context.MODE_MULTI_PROCESS);
editor = prefs.edit();
}
// static methods to set and get preferences
}
Now I'm using this class on a service with separate process and also in my main application process in static way.
Everything is going well, but sometimes all stored data on SharedPreferences instance removed!
How can I solve this problem?
Edit:
Finally I've solved my problem using by IPC.
There is currently no way of safely accessing SharedPreferences on multiple processes, as described in its documentation.
Note: This class does not support use across multiple processes.
After testing a lot with MODE_MULTI_PROCESS, I've three trials to share:
1- Initialize the SharedPreferences once in each process and use it multiple times.
The problem: The values are not reflected in each process as expected. So each process has its own value of the SharedPreferences.
2- Initialize the SharedPreferences in each put or get.
This actually works and the value now is interchangeable between processes.
The problem: sometimes after aggressively accessing the sharedpref, the shared preferences file got deleted with all its content, as described in this issue, and I get this warning in the log:
W/FileUtils﹕ Failed to chmod(/data/data/com.hegazy.multiprocesssharedpref/shared_prefs/myprefs.xml): android.system.ErrnoException: chmod failed: ENOENT (No such file or directory)
You can find why this happens in the issue.
3- Use synchronization to lock the methods that put and get values in the SharedPreferences.
This is completely wrong; synchronization doesn't work across processes. The SharedPreferences is actually using synchronization in its implementation, but that only ensures thread safety, not process safety. This is described very well here.
SharedPreferences itself is not process-safe. That's probably why SharedPreferences documentation says
Note: currently this class does not support use across multiple processes. This will be added later.
I've worked around this by combining:
Providing each process mutually-exclusive access to the SharedPreferences file (such as by using a socket-based locking mechanism)
Re-initialising the SharedPreferences with the MODE_MULTI_PROCESS flag every time you want to use it to bypass in-memory caching
This seems to work OK, but it hasn't been thoroughly tested in the real world, so I don't know if it's perfectly reliable.
You can see a working example I wrote here.
Warning: Looks like MODE_MULTI_PROCESS has been deprecated in Android M. It might stop working in the future.
Using the commit() method store the changes in persistent storage, hence it is slow and would make conflict across multiple call from other processes.
However there is an alternative to this method, you should call the apply() method, this method stores the changes in memory and then in disk storage asynchronously, so it is more reliable.
recalls that the use of context objects as static field, you have the risk of leakage of context because not declare the object in the application class
public class CustomApplication extends Application{
private Prefs prefs;
public void onCreate(){
prefs = new Prefs(this);
}
public Prefs getPrefs(){
return prefs;
}
}
From any context you can get the prefs
((MyApplication)context.getApplicationContext()).getPrefs();
Use a Content Provider which uses SharedPreferences. Example see here: https://github.com/hamsterksu/MultiprocessPreferences
public static int getValore(Context ctx, String contenitore, String chiave, int valore){
try {
SharedPreferences sh = ctx.getApplicationContext()
.getSharedPreferences(contenitore, Context.MODE_MULTI_PROCESS);
//SharedPreferences.Editor editor = sh.edit();
return sh.getInt(chiave, valore);
}catch (Exception ex){
return valore;
}
}
If two processes write data to SharedPreferences, then it might possible all SharedPreferences are reset to default values.
Also you can try to call clear() on the editor before storing val
SharedPreferences.Editor sp = settings.edit();
sp.clear();
sp.putString("Name", "YourName");
sp.commit();

Multiple instance of Sharedpreference gives different value for same field

I am trying to read the value of a field in sharedpreference using two different instances of sharepreferences. While read by using the first instance is giving the correct result, the second read operation using second instance is returning the default values.Why is it so?Am I missing some important concept here?
Code:
public void testMethod(){
SharedPreferences pref1=myContext.getSharedPreferences(PreferenceHelper.MY_PREF, myContext.MODE_PRIVATE);
//Correct value is obtained here...
String value1=pref1.getString("KEY", "");
SharedPreferences pref2=myContext.getSharedPreferences(PreferenceHelper.MY_PREF, myContext.MODE_PRIVATE);
//Incorrect value is obtained here...
String value2=pref2.getString("KEY", "");
}
I am doubting this is due to multiple instances of the same preference.Android documentation states:
Only one instance of the SharedPreferences object is returned to any callers for the same name, meaning they will see each other's edits as soon as they are made.
Does my case relates to concept in this sentence?
Since your invoking commit() and not apply(), one of them isn't saving and you're getting the wrong answer. Check out the docs:
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.
The above from http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#apply()

What are things to keep in mind while using Shared Preferences android?

I am working on a simple android application.
The application has the functionality of user login which is connected to php.
I am successful in getting login functionality done well. What I want now is to save the username so that I can use it anywhere and anytime in my application. After going through some SO threads I came to know that this is doable using android sharedPreferences.
But prior to implementing them I want to know some stuff that I should keep in mind while using sharedPreferences like
what is basic task of shared preferences?
what things to keep in mind while actually using them?
what is proper way to programatically implement them in code?
and finally how to remove them after they are used?
what is basic task of shared preferences?
SharedPreferences are essentially used when you need your application to store persistent data. I consider using it when a Database is (for the sheer purposes of size / data to be stored) isn't really required.
what things to keep in mind while actually using them?
You can save just about anything that you typically require for your application to perform it's task. For example, in a gaming application, you could store the user's scores. However, since the SharedPreferences file/s can be accessed by anyone on a rooted device, you wouldn't want to store passwords. If you absolutely must store them anyway, you should implement your own algorithm to encrypt it. In an app of mine, I store URL's to a user's profile picture on Facebook and Twitter. That is already in the public domain.
what is proper way to programatically implement them in code?
If you are going to use SharedPreference in say, just one or two Activities, you use something like this to add values to the SharedPreference file:
// THE SHAREDPREFERENCE INSTANCE
SharedPreferences sharedPrefs;
// THE EDITOR INSTANCE
Editor editor;
// A CONSTANT STRING TO PROVIDE A NAME TO THE SHAREDPREFERENCE FILE
private static final String PRIVATE_PREF = "some_file_name";
// INSTANTIATE THE SHAREDPREFERENCE INSTANCE
sharedPrefs = getApplicationContext().getSharedPreferences(PRIVATE_PREF, Context.MODE_PRIVATE);
// INSTANTIATE THE EDITOR INSTANCE
editor = sharedPrefs.edit();
// ADD VALUES TO THE PREFERENCES FILE
editor.putLong(UNIQUE_KEY_NAME, VALUE);
editor.putString(UNIQUE_KEY_NAME, VALUE);
editor.putString(UNIQUE_KEY_NAME, VALUE);
editor.putString(UNIQUE_KEY_NAME, VALUE);
// THIS STEP IS VERY IMPORTANT. THIS ENSURES THAT THE VALUES ADDED TO THE FILE WILL ACTUALLY PERSIST
// COMMIT THE ABOVE DATA TO THE PREFERENCE FILE
editor.commit();
To fetch the values out of the file:
String someString = sharedPrefs.getString(UNIQUE_KEY_NAME, null);
long someLong = sharedPrefs.getLong(UNIQUE_KEY_NAME, 0);
If you need to reuse the contents / values from the SharedPreference file, this here is a nice tutorial on creating a helper class that will let any number of Activites to access the values instead of coding the above in every single one of them: http://megasnippets.com/source-codes/java/sharedpreferences_helper_class_android
and finally how to remove them after they are used?
// INSTANTIATE THE EDITOR INSTANCE
editor = sharedPrefs.edit();
// TO CLEAR A SELECT FEW OF THE VALUES:
editor.remove(KEY_FOR_THE_VALUE_TO_BE_REMOVED);
// ALTERNATIVELY, TO CLEAR ALL VALUES IN THE FILE:
editor.clear();
Note: Any SharedPreferences file/s you may create will be removed when the user manually clears the app data from the device's Settings.
Links For Further Reading:
http://www.vogella.com/articles/AndroidFileBasedPersistence/article.html
http://saigeethamn.blogspot.in/2009/10/shared-preferences-android-developer.html
http://www.mybringback.com/tutorial-series/12260/android-sharedpreferences-example/
http://www.androidhive.info/2012/08/android-session-management-using-shared-preferences/
How to Save/Read 'username' from SharedPreferences Persistent Storage
Basic Task:
Persistent storage.
Keep In Mind:
Is there so much data that you might be better off using a database or flat file storage?
Proper Way to Save and Read "username":
String key = "username";
String value = "John Doe";
// Save
SharedPreferences.Editor editor = context.getSharedPreferences(MY_PREFS_NAME, Context.MODE_PRIVATE).edit();
editor.putString(key, value);
editor.commit();
// Read
String def = "";
SharedPreferences settings = context.getSharedPreferences(MY_PREFS_NAME, Context.MODE_PRIVATE);
if(!settings.contains(key)) {
// Warn user that there is nothing to read and/or return a default value: "def"
}
String value = settings.getString(key, def);
About the basic task : you can read on Storage Options at developer.android.com.
About the keep in mind : try to avoid saving sensetive data to your application in shared preferences,because user can easily access the data.
You can find your shared preferences xml file in /data/data/your_application.package.name/shared_prefs/shared_prefs_name.xml
Implementation :
Usualy I am creating class with static methods like this :
public class MySharedPreferences {
private static final String APP_SHARED_PREFS = "my_prefs";
private static final String KEY_LOGIN = "username";
public static void setUsername(Context context, String username) {
SharedPreferences sharedPreferences = context.getSharedPreferences(APP_SHARED_PREFS, Activity.MODE_PRIVATE);
Editor editor = sharedPreferences.edit();
editor.putString(KEY_USERNAME, login);
editor.commit();
}
public static String getUsername(Context context) {
SharedPreferences sharedPreferences = context.getSharedPreferences(APP_SHARED_PREFS, Activity.MODE_PRIVATE);
return sharedPreferences.getString(KEY_USERNAME, null);
}
}

Can I get data from shared preferences inside a service?

I'm developing an android application. I'm using android 2.2
In my application I am capturing GPS data and sending it to service with the 1 hour time interval. If user exits from application it's also working (it is required).
I'm using 2 services (User defined), one for capturing GPS data and other for sending to the server.
Here my doubt
In service, can we use shared preferences.
If we store any data in shared preferences in any activity of the application, will we be able to use that data in service with the help of shared preferences?
You can access the default shared preferences instance, which is shared across all your Activity and Service classes, by calling PreferenceManager.getDefaultSharedPreferences(Context context):
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
This is great for storing simple primitives (like booleans) or serializable objects. However, if you're capturing a lot of location data, you might consider using a SQLite database instead.
I find the solution.
Inside a service we call the following method to get the shared preferences
myapp.bmodel.getApplicationContext().getSharedPreferences("myPrefs_capture_gps_per_hour", Context.MODE_PRIVATE);
In the above code myapp is a object of the application class which is derived from Application
You need a context to get access to shared preferences. The best way is to create MyApplication as a descendant of Application class, instantiate there the preferences and use them in the rest of your application as MyApplication.preferences:
public class MyApplication extends Application {
public static SharedPreferences preferences;
#Override
public void onCreate() {
super.onCreate();
preferences = getSharedPreferences( getPackageName() + "_preferences", MODE_PRIVATE);
For example, if you need access to your preferences somewhere else, you may call this to read preferences:
String str = MyApplication.preferences.getString( KEY, DEFAULT );
Or you may call this to save something to the preferences:
MyApplication.preferences.edit().putString( KEY, VALUE ).commit();
(don't forget to call commit() after adding or changing preferences!)
Yes Shivkumar, you can use your share preferences in any kind of services as normal as you are using in your Activity.
same like
SharedPreferences preferences = getSharedPreferences("<PrefName>",
MODE_PRIVATE);
There are two ways to create instance of SharedPreference:
Case 1:
SharedPreferences preferences = activity.getSharedPreferences("<PrefName>", MODE_PRIVATE);
Case 2:
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
Notice if you create a preference with the same name (case 1) or same context (case 2) even at different places, it's still the same, and can share data, obviously.

Categories

Resources