I'm writing an android app with a preferencesActivity in which selections made in my instance of preferencesActivity affect the values of other preferences items displayed. While I'm able to change the values of the underlying SharedPreferences items pogrammatically, those changed values aren't reflected in the displayed list items until I exit my preferencesActivity and reload it. Below is a stripped down version of my settings class and xml file which illustrate the problem. If a user sets Guitar as the value for the preference with the key instrumentList, I'd like the preference with key tuningChoice to revert to Standard.
//necessary import declarations go here
public class Settings extends PreferenceActivity implements OnSharedPreferenceChangeListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
SharedPreferences app_preferences = PreferenceManager.getDefaultSharedPreferences(this);
app_preferences.registerOnSharedPreferenceChangeListener(this);
}
public void onSharedPreferenceChanged (SharedPreferences sharedPreferences, String key) {
Log.d("onSharedPreferencesChanged", "sharedPreferences changed. key: " + key);
Editor preferencesMod = sharedPreferences.edit();
String instrumentChoice = sharedPreferences.getString("instrumentList", "Guitar");
if(key.equals("instrumentList")) {
Log.d("Settings", "key is instrumentList. chooseTuning before if: " + sharedPreferences.getString("chooseTuning", "no luck"));
if(instrumentChoice.equals("Guitar")) {
preferencesMod.putString("chooseTuning", "Standard");
preferencesMod.commit();
Log.d("Settings", "chooseTuning after if: " + sharedPreferences.getString("chooseTuning", "ciao"));
}
}
}
}
xml file preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="Settings">
<ListPreference android:title="Choose an Instrument" android:key="instrumentList" android:entryValues="#array/instruments" android:entries="#array/instruments"/>
<ListPreference android:title="Choose Tuning" android:key="chooseTuning" android:entryValues="#array/tuningChoices" android:entries="#array/tuningChoices" android:persistent="true"/>
</PreferenceScreen>
I can call addPreferencesFromResource again in my onSharedPreferenceChanged method and that loads a duplicate of all the preferences items, displayed below the old items, with the correct values. If I could figure out some way to cancel out the initial addPreferencesFromResource called during onCreate, I guess I would be set.
Any help would be appreciated, Thanks
I do something along these lines...hopefully it helps:
ListPreference list = (ListPreference) getPreferenceManager().findPreference("myList");
list.setValue(sharedPrefs.getString("myList", "default"));
list.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
sharedPrefs.put("myList", newValue.toString());
return true;
}
});
You need to prevent addPReferencesFromResource from running twice? Is this loading your default values? If so, add an additional SharedPreference called DEFAULTS_LOADED and read its value in on create like: (WARNING PSUEDO CODE):
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences app_preferences = PreferenceManager.getDefaultSharedPreferences(this);
boolean loadDefaults = app_preferences.getBoolean(DEFAULTS_LOADED, true);
if(loadDefaults)
{
addPreferencesFromResource(R.xml.preferences);
Editor editor = app_preferences.edit();
editor.putBoolean(DEFAULTS_LOADED, true);
editor.commit();
}
app_preferences.registerOnSharedPreferenceChangeListener(this);
}
This will prevent you defaults from being written to the shared preferences every time your activity starts. I assume this is at least a portion of your issue.
If anyone comes to this problem, this is the solution:
ListView list = preferenceActivity.getListView();
list.performItemClick(list, 1, list.getItemIdAtPosition(1));
Maybe I am too late for answering this. But, I hope this might help beginner like me.
PackageInfo packageInfo = null;
try {
packageInfo = preference.getContext().getPackageManager().getPackageInfo(preference.getContext().getPackageName(), 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
preference.setSummary(packageInfo.versionName);
Related
Okay so I'm trying to make sense of how Shared Preference works with Preference.
Below is part of an app that works, but I do not understand how it works for the part of Shared Preference.
I have a UserPrefActivity.java containing the following code
public class UserPrefActivity extends PreferenceActivity {
//a preference value change listener that updates the preference summary
//to reflect its new value
private static Preference.OnPreferenceChangeListener
sBindPreferenceSummaryToValueListerner = new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
//gets string value of object
String value = newValue.toString();
Log.e("in sBind Listener", value);
//if the preference is a list preference, get the value at a given index
if (preference instanceof ListPreference) {
//for list preference look up the correct display value
//in the preference entries array
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(value);
//set the summary to reflect the new value
preference.setSummary(index >= 0 ? listPreference.getEntries()[index] : null);
} else {
//set summary to only value
preference.setSummary(value);
}
return true;
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//call the deprecated method to load the preference screen
addPreferencesFromResource(R.xml.user_pref);
//get default Shared preference from preference screen
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(this);
Preference saveNumPizza = findPreference("saveNumPizza");
//set the preference change listener to saveNumPizza
saveNumPizza.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListerner);
sBindPreferenceSummaryToValueListerner.onPreferenceChange(saveNumPizza,
PreferenceManager
.getDefaultSharedPreferences(this)
.getString(saveNumPizza.getKey(), ""));
}
}
In the MainActivity.java, I have the following as part of a bigger piece of code
//gets the default shared preference instance and assign to sharedPrefs for enabled save
// data
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences
(MainActivity.this);
//checks if save order status is true
if (sharedPrefs.getBoolean("saveOrder", false)) {
//do stuff..
}
I have the following UserPref.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:defaultValue="false"
android:key="saveOrder"
android:summary="for quick loading of favourite order"
android:title="Enable Saving Order"/>
<PreferenceCategory android:title="ORDER HISTORY">
<CheckBoxPreference
android:defaultValue="false"
android:key="keepHistory"
android:summary="of pizza orders"
android:title="Keep History"/>
<ListPreference
android:defaultValue="3"
android:dialogTitle="Choose how many to save"
android:entries="#array/number_of_pizza"
android:entryValues="#array/number_of_pizza_values"
android:summary="3 pizza orders"
android:key="saveNumPizza"
android:title="Number of Orders"/>
</PreferenceCategory>
</PreferenceScreen>
I know that in the UserPrefsActivity, I believe in the PreferenceManager.getDefaultSharedPreferences(this) call, the shared preferences is created and obtained if it does not exist, if it does its just obtained.
From what I've noticed with the app, is that on first launch when I get to the settings and launch the UserPrefActivity via intent, the shared preference of the UserPrefActivity is created, containing only the saveNumPizza key. However the minute I click on the other preferences (Checkbox preference) when I look at the shared preference file, I immediately see that the saveOrder key and keepHistory key are automatically saved.
I would just like to know how this automatic saving is exactly done since I am not using an editor to save it to the shared preference, nor am I calling apply or commit.
Thank you,
So I am trying to implement a preferences menu in my app. I used the standard generated template in android studio. THe issue is that now I can't figure out how save the values the user specifies. I thought about using a click listener to determine when a user clicked a checkbox and then getting the actual value of the checkbox and saving that to sharedpreferences, but I can't figure out how to do it.
Does anyone have any suggestions on how use onClick in a preference activity?
OK, we seem to be on the right track about the system storing the values automatically, but whenever I try to reference them from my main class, it always returns null. Here is my code:
boolean trueorfalse = PreferenceManager.getDefaultSharedPreferences(getActivity())
.getBoolean("my_key", false)
;
So I assume you've already defined your Preferences in res --> xml and it looks something like this:
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="my_key"
android:summary="#string/desc_string"
android:title="#string/title_string" />
</PreferenceScreen>
As soon as the user checks or unchecks the CheckBox the systen will automatically create an entry in the default Preference-file which you can access like this:
PreferenceManager.getDefaultSharedPreferences(this)
.getBoolean("my_key", false);
But back to your initial question: If you want to assign an onClick-Listener to your preference you have to do something like this:
Preference myPreference = (Preference) findPreference("my_key");
myPreference .setOnPreferenceClickListener(new OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
// do something
}
});
Note: In this example it isn't a CheckBoxPreference, it's just a simple Preference
I tried the same in my SettingsMenu by implementing OnSharedPreferenceChangeListener
public class SettingsMenu extends PreferenceActivity implements OnSharedPreferenceChangeListener {
#Override
public void onCreate(Bundle savedInstanceState) {
Context context = getApplicationContext();
SharedPreferences menu_settings = PreferenceManager.getDefaultSharedPreferences(context);
menu_settings.registerOnSharedPreferenceChangeListener(this);
...
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
// check the checkboxes
}
}
Hope it helps :)
I have a PreferenceFragment where I have defined a CheckBoxPreference in XML. I need to check this value in a Service, but it always gives me the old value. I noticed the value is correctly changed when I restart the application.
My Preference Fragment :
public class OptionsFragment extends PreferenceFragment
{
public static final String WIFI_ONLY = "wifi";
private SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(MyApplication.getInstance());
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.config);
}
}
My config.xml :
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<CheckBoxPreference
android:defaultValue="true"
android:key="wifi"
android:summary="Check if you want to use wifi only"
android:title="Use Wifi only" />
</PreferenceScreen>
My Service :
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MyApplication.getInstance());
Log.d(TAG, "isWifiOnly : "+settings.getBoolean(OptionsFragment.WIFI_ONLY, true));
The log always return the same value no matter if I change it or not, except if i restart the app. Also, in my MainActivity I have that line in OnCreate():
PreferenceManager.setDefaultValues(getApplicationContext(), R.xml.config, false);
It creates the config file with the default value if needed.
I'm doing something wrong, the question is what ?
I found a solution thanks to this link Managing SharedPreferences in both PreferenceActivity and Service within same app and thanks to Andrew T. :
The issue was the multi process mode. If you have a Service which is declared in the manifest with a android:process="" (which is my case) then it's necessary to set a multi process mode.
Here is what i did :
in PreferenceFragment :
public static final String CONFIG_NAME = "pref";
...
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getPreferenceManager().setSharedPreferencesName(CONFIG_NAME);
getPreferenceManager().setSharedPreferencesMode(Context.MODE_MULTI_PROCESS);
addPreferencesFromResource(R.xml.config);
...
}
My Service :
SharedPreferences settings = MyApplication.getInstance().getSharedPreferences(OptionsFragment.CONFIG_NAME, Context.MODE_MULTI_PROCESS);
and I set the default values in MainActivity this way :
PreferenceManager.setDefaultValues(getApplicationContext(), OptionsFragment.CONFIG_NAME, Context.MODE_MULTI_PROCESS, R.xml.config, false);
And now it works fine. Hope it will help !
Thank you again Andrew T.
I had the same issue for the last days...
I have a preference.xml with my layout and keys and inflate it into a PreferenceFragment while Listening on changes and thereby informing a Service of my Application of any change.
The crucial part is to set the mode of the SharedPreference access right:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
getPreferenceManager().setSharedPreferencesMode(Context.MODE_MULTI_PROCESS);
}
The Context.MODE_MULTI_PROCESS flag makes commits() apply to all accessing processes so even my Service would get direct access to the just changed values.
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
{
if(SettingsManager.setupIsValid(getActivity())){
Intent startServiceIntent = new Intent(getActivity(), IntentService.class);
startServiceIntent.setAction("PREFERENCES_CHANGED");
getActivity().startService(startServiceIntent);
} else {
Toast.makeText(getActivity(), getString(R.string.settings_incomplete), Toast.LENGTH_SHORT).show();
}
}
This will first do check magic and whenever the settings are valid inform the service of the change.
This allows the usage of multiple processes and always current preference values across all processes.
P.S.: direct access then looks like this
SharedPreferences prefs = context.getSharedPreferences(context.getPackageName() + "_preferences", Context.MODE_MULTI_PROCESS);
The program creates preferences the first time but after that it never changes them. I would appreciate assistance in understanding why.
This is the PreferencesScreen where the xml is called.
public class PreferencesScreen extends PreferenceFragment{
private final String TAG = "PreferencesScreen";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "OnCreate");
addPreferencesFromResource(R.xml.prefs);
}
In the preferences I have a ListPreference and a Preference which calls an activity to store emails.
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory android:title="Information Collected">
<ListPreference
android:key="loggins"
android:title="Logs Stored"
android:summary="Choose the top kind of logs do you want to store."
android:dialogTitle="Choose Logs"
android:entries="#array/logs"
android:entryValues="#array/logsValues"/>
</PreferenceCategory>
<PreferenceCategory android:title="Email Configurations">
<Preference
android:key="pushing"
android:title="The Email Activity"
android:summary="Just push">
<intent android:action = "ADDING_EMAIL"/>
</Preference>
</PreferenceCategory>
</PreferenceScreen>
Everything until here. The problems are in the activity called...
public class AddingEmail extends ListActivity implements OnClickListener{
private Set<String> emails;
private EditText emailAdd;
SharedPreferences.Editor editor;
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.addingemail);
Button add = (Button) findViewById(R.id.add);
emailAdd = (EditText) findViewById(R.id.email);
prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
editor = prefs.edit();
prefList = toArrayList(prefs.getStringSet("emailWrongs", null));
add.setOnClickListener(this);
}
public void onClick(View v) {
Set<String> list = prefs.getStringSet("emailWrongs", null);
String newEmail = emailAdd.getText().toString();
if (list==null){ //first time the preferences are called.
emails = new TreeSet<String>();
editor.putStringSet("emailWrongs", emails);
editor.apply();
}
if (newEmail != ""){
emails=prefs.getStringSet("emailWrongs", null);
emails.add(newEmail);
editor.putStringSet("emailWrongs", emails);
editor.apply();
}
}
}
The point is that it always stores the first time well but if I when I add another email the preferences doesnt't change. They looks like they change because if I printed them they show all the emails I add but the preference file doesn't change (Checking it in the File Explorer). And if i reboot or close and open again, the preferences are only with the first email I add.
The thing is if i back to and change the preference of the ListPreference, then it stores all the changes even the emails I added.
Hope I was clear, it has a lot of code because i wanted to be very explicit.
Thank you for the help.
After more than a week looking for the mistake I found it.
I think this can be helpful for a lot of people who had the same trouble.
The problem was that when I call the preferences to get the String Set, it only reference the list and not make a copy of it. So I have to create a new list and add all the elements stored before and also add the new element and then with the editor change the preferences with the new list.
The code is like this:
Set<String> list = prefs.getStringSet("emailWrongs", null);
Set<String> newList = new TreeSet<String>();
String newEmail = emailAdd.getText().toString();
if (newEmail != ""){
if (list != null){
for(String each: list){
newList.add(each);
}
}
newList.add(newEmail);
editor.putStringSet("emailWrongs", newList);
editor.apply();
}
For storing a Stringset, a better way to do this is to first remove the last SharedPreferences value, then save the new one with the same key. Like this:
defaultSharedPreferences.edit().remove("keysValue").commit();
defaultSharedPreferences.edit().putStringSet("keysValue",likesset).commit();
I use some CheckBoxPreferences, but they are not indepentent. That means, wenn I change one CheckBoxPreference, others are fixed. I use the following code:
public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
Context context = getApplicationContext();
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.registerOnSharedPreferenceChangeListener(this);
}
#Override
public void onSharedPreferenceChanged(SharedPreferences sharedPrefs, String key) {
SharedPreferences.Editor editor = sharedPrefs.edit();
if ((key.equals("A")) & (key.equals("B"))) {
editor.putBoolean("C", true);
editor.commit();
}
}
}
After this the CheckBoxPreference "C" has a new value, but I can't see it. How can I update the screen with the new values?
By using a subclass of PreferenceActivity you do not have to handle the updating of the preferences UI. You define the preferences in the resource file loaded by addPreferencesFromResource() and the Activity will be rendered accordingly. Changes will be persisted automatically and should be visible immediately. You do not have to register your preferences Activity as a SharedPreferences.OnSharedPreferenceChangeListener.
When onSharedPreferenceChanged() is called the new value is already saved to the preferences.
This notification is for other Activities than the subclasses of PreferenceActivity. To know how to access the saved preferences you need to look at the file in res/xml/settings.xml it should contain android:key attributes. The attribute values give you the key to the preference.
You can retrieve the value via the following:
PreferenceManager.getDefaultSharedPreferences(aContext).getString(key, "");