Reputation: 829
I am currently working on an app with SharedPreferences and I am trying to dynamically change the value that appears on the Prefs activity screen. On the screen I have a preferencelistview which contains months of the year and two edit boxes to store info in relation to chosen month. Upon selection of a month, I want a few things to happen:
So, basically, my problem is with item#2. I have a function that checks when a new month is selected from the list:
public void setMonth(SharedPreferences sp) {
ContentValues cv = new ContentValues();
cv.clear();
int sel_month = Integer.valueOf(sp.getString("pActivityMonth", String.valueOf(this.month))); //listvew works with strings, convert to int
int stored_new = 0; //default value
int stored_ren = 0; //default value
Log.d(TAG, String.valueOf(sel_month));
String[] col = { Database.C_MONTH, Database.C_QNEW, Database.C_QRENEW };
String[] arg = { String.valueOf(sel_month) };
Cursor c = db.query(Database.RR_TABLE, col, Database.C_MONTH + "=?", arg, null, null, null);
if (c.getCount()<1) { //New month, insert row
cv.put(Database.C_MONTH, sel_month);
db.insertWithOnConflict(Database.RR_TABLE, null, cv, SQLiteDatabase.CONFLICT_IGNORE);
} else { //row exists, get stored values
Log.d(TAG, "cursor count: " + String.valueOf(c.getCount()));
c.moveToFirst();
stored_new = c.getInt(c.getColumnIndex(Database.C_QNEW));
stored_ren = c.getInt(c.getColumnIndex(Database.C_QRENEW));
Log.d(TAG, "stored_new: " + String.valueOf(stored_new));
}
//Change edittext preferences to stored values
editor.putString("pNewQuota", String.valueOf(stored_new));
editor.putString("pRenewQuota", String.valueOf(stored_ren));
editor.apply();
editor.commit();
}
So, I select a new month (july), click on one of the edittext options to update the info (lets say I entered 20), then select a different month (August), with a default value of 0. If I then click on the edittext again, the dialog continues to show 20 as opposed to 0. If I change this 0 to something else, it stores in the correct row of the database, but then this value continues to persist after changing to another month (say, back to July). My Logcat shows that the function is grabbing the correct values, and that the putString is being run. Is the PreferenceScreen not able to refresh itself? Thanks for any help.
Upvotes: 0
Views: 2238
Reputation: 6510
If I understand correctly, you appear to have a PreferenceActivity which is using both SharedPreferences and an SQLiteDatabase to persist/save the same data. While a PreferenceActivity seems like a pre-built ListView designed for data entry, its actually a lot more: the PreferenceActivity will automatically save and load the Preferences to SharedPreferences, which is a special datastore assigned to your application and managed by the Android OS.
Although intended to store preferences, you could use SharedPreferences to persist some data if you want; either automatically via Preferences, or manually with calls to an editor. You can interrupt and/or modify this persistence in a number of ways, such as creating a preference subclass to replace the behaviors, the use of an OnPreferenceChangeListener to modify behaviors, or toggling persistence via a call to setPersistent(boolean).
An alternative to using PreferenceActivity in this way would be to create an Activity with an AdapterView, or perhaps a ListActivity, and use SimpleCursorAdapter to automate binding the data to the view.
To answer your question regarding persisting changes to SharedPreferences in a PreferenceActivity, I've provided some roughly outlined some sample code in context and outlined a couple potential trouble spots. It is not intended to represent a usable solution so much as guve an idea of what you'll need and where, in what I hope is a clear (if verbose) manner that shouldn't be too difficult to adapt to your project.
/* Preference value modification example.
* This is a code sample with some context, not a solution.
* @author codeshane.com
* */
public class StackOverflow_Question_11513113 extends PreferenceActivity {
/*
*/
class MyPreferenceActivity extends PreferenceActivity {
//Preference keys that were either set in xml, or possibly in source via .setKey():
private final String pref_group_key = "some_prefs_key";
private final String list_pref_key = "some_list_key";
private final String edittext_pref_key = "some_edittext_key";
private PreferenceActivity mPreferenceActivity; /* the activity */
private SharedPreferences mSharedPreferences; /* auto-saving preferences */
private Editor mEdit;
private PreferenceScreen mPreferenceScreen; /* root of the preference hierarchy */
private PreferenceGroup mPreferenceGroup; /* optional grouping of preferences */
private ListPreference mListPreference; /* a pop-up selectable-items-list */
private EditTextPreference mEditTextPreference; /* a pop-up text entry box */
private int stored_new;
private int stored_ren;
/* ... */
public void setMonth() { /*SharedPreferences sp*/
/* ... */
//int stored_new = 0; //default value
//int stored_ren = 0; //default value
/* ... */
/* Should only call either apply() or commit(), not both; calling a .commit() after an .apply() can block the thread (always fun),
* not to mention they essentially do the same thing, just synchronously vs asynchronously.
* http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#apply()
* */
// mEdit.apply(); //API level 9+, void, asynchronous.
// mEdit.commit(); //API level 1+, returns boolean, synchronous.
}
/* ... */
@Override
public void onCreate(Bundle savedInstanceState) {
/* Called once when the Activity is created. */
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.affirm_prefs);
/* ... */
}
@Override
protected void onResume() {
super.onResume();
/* Called when the Activity is created or comes to foreground. */
if (null==mSharedPreferences){init(this);}
mSharedPreferences.registerOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
/* manually load data from shared preferences that IS NOT REPRESENTED
* by a Preference already, or for which Persistent has been manually
* set to false. */
stored_new = mSharedPreferences.getInt("stored_new", 0); //If not found, assigns a default value of 0.
stored_ren = mSharedPreferences.getInt("stored_ren", 0); //If not found, assigns a default value of 0.
}
@Override
protected void onPause() { /* Called when the Activity goes to background. */
super.onPause();
mSharedPreferences.unregisterOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
/* manually save data to shared preferences that IS NOT REPRESENTED
* by a Preference already, or for which Persistent has been manually
* set to false. */
mEdit.putInt("stored_new", stored_new);
mEdit.putInt("stored_ren", stored_ren);
mEdit.commit();
}
private boolean init(PreferenceActivity activity){
mPreferenceActivity = activity; // or PreferenceActivity.this;
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
mPreferenceScreen = mPreferenceActivity.getPreferenceScreen();
mPreferenceGroup = (PreferenceGroup)mPreferenceScreen.findPreference(pref_group_key);
mListPreference = (ListPreference)mPreferenceScreen.findPreference(list_pref_key);
mEditTextPreference = (EditTextPreference)mPreferenceScreen.findPreference(edittext_pref_key);
return true;
}
/* When registered to a preference, this listener is notified of changes before saving.
* */
OnPreferenceChangeListener onPreferenceChangeListener = new OnPreferenceChangeListener(){
public boolean onPreferenceChange(Preference preference, Object newValue) {
boolean persistNewValue = true;
/* This occurs when a user has changed a preference, but before it is persisted */
/* this is a good place for your "setMonth" logic,
* at least in a PreferenceActivity*/
updateElement(preference, newValue);
changeMoreStuffBonusMethod(preference);
return persistNewValue;
}};
/* When registered to SharedPreferences, this listener is notified of all saves to SharedPreferences, even if the data is the same
* */
OnSharedPreferenceChangeListener onSharedPreferenceChangeListener = new OnSharedPreferenceChangeListener(){
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
}
};
private boolean updateElement(Preference prefUpdating, Object value){
if (null==prefUpdating) return false;
/* This function is for manually changing the value before it
* is saved by the PreferenceActivity. */
/* ... */
/* Can match exact instances, such as our mListPreference */
if (mListPreference.equals(prefUpdating)) {
/* set selected item by item's index id */
mListPreference.setValueIndex(0);
/* or set selected item by item's key*/
mListPreference.setValue("item_key");
}
/* Can also match by Class, such as any EditTextPreference */
if (prefUpdating instanceof EditTextPreference){
EditTextPreference etp = (EditTextPreference)prefUpdating;
String oldText = etp.getText();
etp.setText("Some new text in edit text box"); /* or */
etp.setText(String.valueOf(stored_new)); /* or */
etp.setText(oldText.trim()); /* remove leading/trailing whitespace */
etp.setText(dataModel.get(prefUpdating.getKey())); /* if you use a model.. */
}
/* ... */
}
private void changeMoreStuffBonusMethod(Preference prefUpdating){
/* Change the preference text */
prefUpdating.setTitle("Click Me!");
prefUpdating.setSummary("I am a cool preference widget!");
/* Change the pop-up list (not items) text */
if (prefUpdating instanceof ListPreference){
ListPreference lp = (ListPreference)prefUpdating;
lp.setDialogTitle("I am the pop-up.");
lp.setDialogMessage("Select something from my list.");
}
/* If persistent, PreferenceActivity should handle saving: */
Log.v(TAG,prefUpdating.getClass().getSimpleName()+".isPersistent="+String.valueOf(mListPreference.isPersistent()));
}
}
}
Upvotes: 1