I tried to store some values in ArrayList by SharedPreferences by the following code:
public static String jsonSavePracticeResult;
private SharedPreferences sharedPreferencesSaveResults = PreferenceManager.getDefaultSharedPreferences(this);
public void savePracticeResults(ArrayList<KeepPracticeResultsModel>
arrayListPracticeResult) {
Gson gson = new Gson();
jsonSavePracticeResult = gson.toJson(arrayListPracticeResult);
SharedPreferences.Editor editorSharedPreferencesSaveResults;
editorSharedPreferencesSaveResults =
sharedPreferencesSaveResults.edit();
editorSharedPreferencesSaveResults.clear();
editorSharedPreferencesSaveResults
.putString("donePracticeList",jsonSavePracticeResult);
editorSharedPreferencesSaveResults.apply();
}
After that, I retrieved values by the following code:
public ArrayList<KeepPracticeResultsModel> getSavedPracticeResults(){
jsonSavePracticeResult = sharedPreferencesSaveResults.getString("donePracticeList", jsonSavePracticeResult);
Gson gson = new Gson();
Type type = new TypeToken<ArrayList<KeepPracticeResultsModel>>() {}.getType();
keepPracticeResultsModels = gson.fromJson(jsonSavePracticeResult, type);
return keepPracticeResultsModels;
}
When app is open, it works fine, but when you try to close app from recent apps, and after that you open app again, SharedPreferences values are lost and jsonSavePracticeResult is Null!
Also I called getSavedPracticeResults() in onResume() and onPause().
I did all of the solutions that existed in StackOverflow but it's happening again!
Have you tried using .commit() instead?
Change
editorSharedPreferencesSaveResults.apply();
to
editorSharedPreferencesSaveResults.commit();
The reason being that .apply() writes in the background, asynchronously; wherever as .commit() will write right away. So, if you're closing your app, you want to quickly save these changes before the app is closed.
Related
I am working on shared Preferences. Basically, I am saving ArrayList to shared preferences which are working fine. Now I want to retrieve the ArrayList from Shared preferences but I am getting null. ArrayList is retrieving from preferences and also showing it's size. but data is not being set to string. How I retrieve the ArrayList from shared Preferences.
here is my code
public void saveRootCategory(List<Category> categories){
preferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, MODE_PRIVATE);
editor = preferences.edit();
editor.putInt("RootCategory",categories.size());
for (int i=0;i<categories.size();i++){
setData(categories.get(i));
}
editor.apply();
}
public void setData(final Category category){
categoryId = category.getId();
categoryName = category.getCategoryName();
editor.putInt("CategoryId",categoryId);
editor.putString("CategoryName",categoryName);
}
public ArrayList<String> getRootCategoy() {
preferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, MODE_PRIVATE);
ArrayList<String> rootCategories = new ArrayList<>();
rootCategories.clear();
int size = preferences.getInt("RootCategory", 0);
for(int i=0;i<size;i++) {
int Id = preferences.getInt("CategoryId" + i,0);
String name = preferences.getString("CategoryName" + i ,"");
rootCategories.add(String.valueOf(Id));
rootCategories.add(name);
}
return rootCategories;
}
I used to have the same null problem
Here's how I solved it
I have an arrayList named language
language = new ArrayList<String>
I had to add everything the user writes on the edittext on button click not repeating any redundant value
if(!language.contains(value)) {
language.add(value);
}
To save this arraylist I created a hashSet
Set<String> set = new HashSet<String>();
and save all of them onPause
set.addAll(language);
.putStringSet("yourKey", set);
.commit();
and retrive it back to language array list onCreate
prefs=this.getSharedPreferences("yourPrefsKey",Context.MODE_PRIVATE);
edit=prefs.edit();
set = prefs.getStringSet("yourKey", null);
language = new ArrayList<String>(set);
edit.remove("yourKey").commit();
remember to remove everytime or it will again create null
You are missing the index in setData. Change it to
public void setData(final Category category, int index){
categoryId = category.getId();
categoryName = category.getCategoryName();
editor.putInt("CategoryId" + index, categoryId);
editor.putString("CategoryName" + index, categoryName);
}
As you are trying to save the ArrayList into the share preference.
I Suggest you can use PaperDB Library.
Which is very fast and directly save your ArrayList same as preference doing.
You can also use it to store the Primitive datatypes and model class directly.
Note: It also reduces the code lines.
Add some breakpoints on setData() -> editor.putInt("CategoryId",categoryId); and debug your code are necessary.
BTW, it seems that there's no difference you call either editor.apply() or editor.commit() running on API 9 or above devices.
Replace your both methods with these:
public void saveRootCategory(List<Category> categories){
preferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, MODE_PRIVATE);
editor = preferences.edit();
editor.putString("RootCategory",new Gson().toJson(categories));
editor.apply();
}
public ArrayList<Category> getRootCategoy() {
preferences = mCtx.getSharedPreferences(SHARED_PREF_NAME, MODE_PRIVATE);
String data = preferences.getString("RootCategory","");
return new Gson().fromJson(data, new TypeToken<List<Category>>(){}.getType());
}
No third party library needed use Gson(inbuilt) library which can easily do what you want to achieve.
public void setData(final Category category)
The method use the same key("CategoryId", "CategoryName") to save every item in the list.
However, you use "CategoryId" + index to get the value from SharedPreference.
Obviously, you can never get the right answer in this way...
#Murat's answer correct the method, and it can work well.
But I don't think it's a good way to save a List. If you do want to use SP to save Lists, I suggest Gson or any other way to translate your object into String first. It will work better.
I am trying to store and retrieve values in shared preferences but first time when I open the app, the shared preference value is NULL. From next time, it shows the values of previous key.
This is my code,
SharedPreferences sharedPreferences;
SharedPreferences.Editor editor;
Set<String> set;
sharedPreferences = getApplicationContext().getSharedPreferences(mypreference, Context.MODE_PRIVATE);
databaseReferenceImages.child(postkey).addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
SharedPreferences.Editor editor = sharedPreferences.edit();
Set<String> sharedlist = new HashSet<String>();
sharedlist.addAll(second);
editor.putStringSet("notifications", sharedlist);
editor.apply();
for (String a : sharedlist) {
Log.d("thesharedlist", a);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
set = sharedPreferences.getStringSet("notifications", null);
if (set != null) {
for (String a : set) {
Log.d("thesetis", a);
}
}
Here I want the values for a particular "POSTKEY"(Poskey will be different for each post)
I want to get the value of array list or "SET" outside of onDataChange method so I used shared Preferences. Its working fine for a String but not for Array list or Set. The following problem occurs,
When I open the app for the first time and click a particular post,
the value of the shared preference value which is returned is NULL.
When I open the same post for the second time, the values are
returning perfectly.
When I open second post ,the values of
previous post are returning.
When I open the first post again, the values of second post are returning.
I don't know where I am wrong. I tried clearing the values of shared preferences each time the app opens but the same problem occurs. I even followed this link but nothing worked. Any help would be great. Thanks in advance.
If you don't want to get null first time, you can do one of these 2 things:
1- call getStringSet differently
sharedPreferences.getStringSet("notifications", "it isn't saved yet!");
2- save default value to sharedpreference before getStringSet
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putStringSet("notifications", sharedlist);
editor.apply();
If you want to get current post not previous one, you should save it before. my guess is that you click on post number one and it's stored in sharedpreference and when you want to check the second one, it returns first one.
I have solved the issue by storing it in sharedpreference after 1500ms.
This is my code,
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
set = sharedPreferences.getStringSet("notifications", null);
if (set != null) {
for (String a : set) {
Log.d("thesetis", a);
}
}
}
}, 1500);
So we're working on this Android app. We've got a login activity that receives some information when the user logs in successfully. We've got a class called SessionManager that handles saving said data to SharedPreferences.
SessionManager always retrieves SharedPreferences from the same file always. It's hardcoded in there.
public SessionManager(Context context) {
this.preferences = context.getSharedPreferences(PREFERENCE_NAME, 0);
this.editor = this.preferences.edit();
this.jsonParser = new Gson();
}
The jsonParser is there so we can save the info as a json object.
public final void storeProfile(UserProfile profile) {
this.editor.putString(STORAGE_KEY, this.jsonParser.toJson(profile));
this.editor.commit();
}
private static final String STORAGE_KEY = "PROFILE";
private String getStoredValue() {
return this.preferences.getString(STORAGE_KEY, null);
}
public UserProfile getStoredProfile() {
String val = getStoredValue();
return (val == null) ? null : this.jsonParser.fromJson(val, UserProfile.class);
}
In theory, this should mean we should be able to store the profile in one activity, then get it back in another activity, right?
Except that's not happening! It looks like I can only retrieve saved information in the same activity where it was saved!
I call storeProfile() in the login activity, then getStoredProfile() in another activity, and it returns null.
I call storeProfile() in the login activity, then getStoredProfile() in the login activity, and it returns the stored profile. It also works if two different SessionManager instances call storeProfile() and getStoredProfile().
I set the stored profile manually in the other activity, and it retrieves the manually stored profile just fine.
Is there some scope rule or something to SharedPreferences that I'm missing?
Turns out I'm a fool and I was accidentally wiping my preferences every time I tried to get them.
My sharedPreferences does not persist after I close the app. It always leaves the default 4 that I add the first time the app runs.
static public Boolean addFavoriteItem(Integer itemId, Context c) {
SharedPreferences s = PreferenceManager.getDefaultSharedPreferences(c);
Set<String> list = new HashSet<>();
list = s.getStringSet("favItems",list);
list.add(Integer.toString(itemId));
s.edit().putStringSet("favItems",list).apply();
Log.d("listNowAdd:",list.toString());
return true;
}
static public Boolean removeFavoriteItem(Integer itemId, Context c) {
SharedPreferences s = PreferenceManager.getDefaultSharedPreferences(c);
Set<String> list = new HashSet<>();
list = s.getStringSet("favItems",list);
list.remove(Integer.toString(itemId));
s.edit().putStringSet("favItems",list).apply();
Log.d("listNowRemove:",list.toString());
return true;
}
It does work temporarily, even after the activity is restarted, but not after the app is closed and reopened, any ideas?
You cannot modify the StringSet returned by SharedPreferences as documented:
Note that you must not modify the set instance returned by this call. The consistency of the stored data is not guaranteed if you do, nor is your ability to modify the instance at all.
Essentially what happens is that you're modifying the Set owned by SharedPreferences. It "works" while the app is running since the same (modified by you) Set is kept in memory. When you're trying to save the changes, shared preferences implementation compares the values using equals() and of course the set is equal with itself, and therefore no changes are actually saved.
You can create a new Set<String> e.g. HashSet<String> and addAll() the set you retrieved from shared preferences and do your modifications on this copy.
A set of questions about SharedPreferences that I was looking for:
What, Why, When?
How does it work inside?
The Best Practice to use it?
Only some of those question were answered here. That's why I made some investigations, and tests.
As I've answered on my own question I've decided to share answer with other people.
I've wrote a little article that can also be found here.
Best Practice: SharedPreferences
Android provides many ways of storing application data. One of those ways leads us to the SharedPreferences object which is used to store private primitive data in key-value pairs.
All logic are based only on three simple classes:
SharedPreferences
SharedPreferences.Editor
SharedPreferences.OnSharedPreferenceChangeListener
SharedPreferences
SharedPreferences is main of them. It's responsible for getting (parsing) stored data, provides interface for getting Editor object and interfaces for adding and removing OnSharedPreferenceChangeListener
To create SharedPreferences you will need Context object (can be an application Context)
getSharedPreferences method parses Preference file and creates Map object for it
You can create it in few modes provided by Context, it's strongly recommended to use MODE_PRIVATE because creating world-readable/writable files is very dangerous, and likely to cause security holes in applications
// parse Preference file
SharedPreferences preferences = context.getSharedPreferences("com.example.app", Context.MODE_PRIVATE);
// get values from Map
preferences.getBoolean("key", defaultValue)
preferences.get..("key", defaultValue)
// you can get all Map but be careful you must not modify the collection returned by this
// method, or alter any of its contents.
Map<String, ?> all = preferences.getAll();
// get Editor object
SharedPreferences.Editor editor = preferences.edit();
//add on Change Listener
preferences.registerOnSharedPreferenceChangeListener(mListener);
//remove on Change Listener
preferences.unregisterOnSharedPreferenceChangeListener(mListener);
// listener example
SharedPreferences.OnSharedPreferenceChangeListener mOnSharedPreferenceChangeListener
= new SharedPreferences.OnSharedPreferenceChangeListener() {
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
}
};
Editor
SharedPreferences.Editor is an Interface used for modifying values in a SharedPreferences object. All changes you make in an editor are batched, and not copied back to the original SharedPreferences until you call commit() or apply()
Use simple interface to put values in Editor
Save values synchronous with commit() or asynchronous with apply which is faster. In fact of using different threads using commit() is safer. Thats why I prefer to use commit().
Remove single value with remove() or clear all values with clear()
// get Editor object
SharedPreferences.Editor editor = preferences.edit();
// put values in editor
editor.putBoolean("key", value);
editor.put..("key", value);
// remove single value by key
editor.remove("key");
// remove all values
editor.clear();
// commit your putted values to the SharedPreferences object synchronously
// returns true if success
boolean result = editor.commit();
// do the same as commit() but asynchronously (faster but not safely)
// returns nothing
editor.apply();
Performance & Tips
SharedPreferences is a Singleton object so you can easily get as many references as you want, it opens file only when you call getSharedPreferences first time, or create only one reference for it.
// There are 1000 String values in preferences
SharedPreferences first = context.getSharedPreferences("com.example.app", Context.MODE_PRIVATE);
// call time = 4 milliseconds
SharedPreferences second = context.getSharedPreferences("com.example.app", Context.MODE_PRIVATE);
// call time = 0 milliseconds
SharedPreferences third = context.getSharedPreferences("com.example.app", Context.MODE_PRIVATE);
// call time = 0 milliseconds
As SharedPreferences is a Singleton object you can change any of It's instances and not be scared that their data will be different
first.edit().putInt("key",15).commit();
int firstValue = first.getInt("key",0)); // firstValue is 15
int secondValue = second.getInt("key",0)); // secondValue is also 15
When you call get method first time it parses value by key and adds this value to the map. So for second call it just gets it from map, without parsing.
first.getString("key", null)
// call time = 147 milliseconds
first.getString("key", null)
// call time = 0 milliseconds
second.getString("key", null)
// call time = 0 milliseconds
third.getString("key", null)
// call time = 0 milliseconds
Remember the larger the Preference object is the longer get, commit, apply, remove and clear operations will be. So it's highly recommended to separate your data in different small objects.
Your Preferences will not be removed after Application update. So there are cases when you need to create some migration scheme. For example you have Application that parse local JSON in start of application, to do this only after first start you decided to save boolean flag wasLocalDataLoaded. After some time you updated that JSON and released new application version. Users will update their applications but they will not load new JSON because they already done it in first application version.
public class MigrationManager {
private final static String KEY_PREFERENCES_VERSION = "key_preferences_version";
private final static int PREFERENCES_VERSION = 2;
public static void migrate(Context context) {
SharedPreferences preferences = context.getSharedPreferences("pref", Context.MODE_PRIVATE);
checkPreferences(preferences);
}
private static void checkPreferences(SharedPreferences thePreferences) {
final double oldVersion = thePreferences.getInt(KEY_PREFERENCES_VERSION, 1);
if (oldVersion < PREFERENCES_VERSION) {
final SharedPreferences.Editor edit = thePreferences.edit();
edit.clear();
edit.putInt(KEY_PREFERENCES_VERSION, currentVersion);
edit.commit();
}
}
}
SharedPreferences are stored in an xml file in the app data folder
// yours preferences
/data/data/YOUR_PACKAGE_NAME/shared_prefs/YOUR_PREFS_NAME.xml
// default preferences
/data/data/YOUR_PACKAGE_NAME/shared_prefs/YOUR_PACKAGE_NAME_preferences.xml
Android guide.
Sample Code
public class PreferencesManager {
private static final String PREF_NAME = "com.example.app.PREF_NAME";
private static final String KEY_VALUE = "com.example.app.KEY_VALUE";
private static PreferencesManager sInstance;
private final SharedPreferences mPref;
private PreferencesManager(Context context) {
mPref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
}
public static synchronized void initializeInstance(Context context) {
if (sInstance == null) {
sInstance = new PreferencesManager(context);
}
}
public static synchronized PreferencesManager getInstance() {
if (sInstance == null) {
throw new IllegalStateException(PreferencesManager.class.getSimpleName() +
" is not initialized, call initializeInstance(..) method first.");
}
return sInstance;
}
public void setValue(long value) {
mPref.edit()
.putLong(KEY_VALUE, value)
.commit();
}
public long getValue() {
return mPref.getLong(KEY_VALUE, 0);
}
public void remove(String key) {
mPref.edit()
.remove(key)
.commit();
}
public boolean clear() {
return mPref.edit()
.clear()
.commit();
}
}
Yakiv has mentioned everything about preferences so neatly and nicely. I just want to add one more point. While editing data in shared preferences we usually do
mPref.edit()
which creates a new object of SharedPreferences.Editor type every time which can result in unnecessary objects in memory. So you can maintain a reference to editor object too and save memory and object creation time and corresponding garbage collection time.