I am now creating a PreferenceFragment with nested PreferenceScreen.
The preferences_layout.xml looks like below
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="#string/preference_setting_title" >
<SwitchPreference
android:key="#string/pref_key_switch"
android:title="#string/title__preference"
android:summary="#string/summary_title_preference"
android:defaultValue="true" />
<CheckBoxPreference
android:key="#string/pref_key_auto_enable"
android:title="#string/title_auto_enable_preference"
android:summary="#string/summary_auto_enable_preference"
android:dependency="#string/pref_key_switch"
android:defaultValue="true" />
<PreferenceScreen
android:key="#string/pref_key_enabled_items"
android:title="#string/title_enabled_items"
android:summary="#string/summary_enabled_items"
android:dependency="#string/pref_key_switch" >
</PreferenceScreen>
</PreferenceScreen>
The nested PreferenceScreen perference items will be dynamically added on that PreferenceScreen onClick.
Due to need to check the items already exist before adding a new one, so i use the following ways to check:
int count = enabledPreferenceScreen.getPreferenceCount();
for (int i = 0 ; i < count ; ++i) {
//Do the check with new one
}
All works ok. But the problem is that when this setting activity is destroyed and relaunch again, enabledPreferenceScreen.getPreferenceCount() will become 0.
So i check with the app/shared_prefs/xxxx.xml, the values are saved, but the problem is that there is no nested screen hierarchy information in that store value xml.
How to solve this issue? Rebuild the PreferenceScreen from the preference_layout.xml cannot rebuild the daynamic add items preferences.
Is it possible to save the nested PreferenceScreen data into another /shared_prefs/xxx2.xml? How to achieve it?
Thanks a lot.
Related
I have two roughly connected issues in my new Android app regarding the Settings. The former is the need to retrieve the information from the preferences without displaying the specific setting activity by performing some:
addPreferencesFromResource(R.xml.preferences);
in another activity.
Is it possible to do it or how else may I retrieve the data without displaying the activity, or is it possible to start the activity without displaying it?
The latter more distressing one is that even in the SettingActivity, when I call that function I recently started getting a crash complaining:
java.lang.ClassCastException: java.lang.Float cannot be cast to java.lang.String
Like if something internal were set somehow expecting something. What may I do and in particular how may I reset this sort of hidden structure?
This is my xml file: if I just keep the entries in the former category it does not crash, if I add any field in the latter it does:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="#string/switches"
android:key="switches">
<EditTextPreference
android:key="night_switch_start"
android:summary="#string/ext_night_switch_start"
android:defaultValue="22"
android:title="#string/night_switch_start" />
<EditTextPreference
android:key="day_switch_start"
android:summary="#string/ext_day_switch_start"
android:defaultValue="6"
android:title="#string/day_switch_start"/>
</PreferenceCategory>
<PreferenceCategory
android:title="#string/tokens"
android:key="tokens">
<EditTextPreference
android:key="token_day"
android:summary="#string/ext_token_day"
android:defaultValue="3"
android:title="#string/token_day" />
</PreferenceCategory>
</PreferenceScreen>
Thanks, Fabrizio
For you first question, you can retrieve a preference saved in a PreferenceActivity by calling PreferenceManager#getDefaultSharedPreferences(Context). This is a static method, so you can have in your Activity something like:
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
About your second question, I'm not sure what is happening. Try cleaning the project before you run it again.
I answer here to be able to show my code better: this is the first summarizing part of the xml file I suspect might have problems:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="#string/switches"
android:key="switches">
<EditTextPreference
android:key="night_switch_start"
android:summary="#string/ext_night_switch_start"
android:defaultValue="22"
android:inputType="numberDecimal"
android:title="#string/night_switch_start" />
<EditTextPreference
android:key="day_switch_start"
android:summary="#string/ext_day_switch_start"
android:defaultValue="6"
android:inputType="numberDecimal"
android:title="#string/day_switch_start"/>
</PreferenceCategory>
<PreferenceCategory
android:title="#string/tokens"
android:key="switches">
<EditTextPreference
android:key="token_day"
android:summary="#string/ext_token_day"
android:defaultValue="3"
android:inputType="numberDecimal"
android:title="#string/token_day" />
</PreferenceCategory>
</PreferenceScreen>
My code is very simple: the crashing setting part is the following.
public class SettingsActivity extends PreferenceActivity {
private static final String LOG_TAG = "preferences";
public static class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener{
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
}
...
}
While the code loading the string and finding "mostly" empty strings is:
sharedPref= PreferenceManager.getDefaultSharedPreferences(Dashboard.dashboard);
startDayTime=Integer.parseInt(sharedPref.getString("day_switch_start", "")); //correct value
startNightTime=Integer.parseInt(sharedPref.getString("night_switch_start", "")); //empty string thereafter rising an exception.
Also, when I tried leaving just the first two EditText, so not to have the crash, the Setting activity had the correct value for day_switch_start and again an empty string in the night_switch_start field.
When I do getAll() I get the correct values:
{start_night_time=6, day_switch_start=6, notifications_new_message_ringtone=content://settings/system/notification_sound, notifications_new_message=true, second_rate_limit=24.0, third_rate_fare=1.6, token_day=6.0, token_night=6.0, night_switch_start=22, token_holiday=6.0, start_day_time=6, start_night_switch=John Smith, example_checkbox=true, example_text=John Smith, notifications_new_message_vibrate=false, example_list=-1, first_rate_fare=1.1, first_rate_limit=11.0, max_speed_for_time=20.0, sync_frequency=180, second_rate_fare=1.3, timed_fares=27.0, cooperative=}
Yet, when I try to get the value of them either with:
startDayTime=Integer.parseInt(sharedPref.getString("night_switch_start", "")); or
startNightTime=sharedPref.getInt("night_switch_start", 0);
I retrieve an empty string in both cases.
Half of the answer: clearing the cache of the phone removes all the funny fields and does not crash any longer the setting activity, nor the loading of its values by:
startNightTime=Integer.parseInt(sharedPref.getString("night_switch_start", ""));
The old form:
startNightTime=sharedPref.getInt("night_switch_start", 0);
still crashes, notwithstanding the values seem numeral. Not a big deal, though.
The unanswered problem is how to load the settings from the xml file without entering the SettingsActivity performing:
addPreferencesFromResource(R.xml.preferences);
Is it possible to run the function from outside that activity or is it possible to start the activity without visualizing it to the user?
I have searched here and looked at samples but haven't yet found an answer to what is essentially a simple problem. Depending on the choice made in a preceding ListPreference, I want to build a preference screen of CheckBoxPreferences dynamically in code, which is then shown when I click on a simple preference with a click listener. The list and number of check boxes will be different in each case.
This is where I have got to so far - just a simple bit of code to test the concept in the onClick listener, but how to get the check box preference screen to appear? There must be a simple explanation why it doesn't. What am I doing wrong?
Part of my xml code:
<PreferenceCategory android:title="Filters">
<PreferenceScreen android:key="FilterScreen"
android:title="Filters" android:summary="Click to change filter settings">
<ListPreference android:title="Filter type"
android:summary="Set to: Gliding"
android:key="filterType"
android:defaultValue="0"
android:entries="#array/filterTypeOptions"
android:entryValues="#array/filterTypeValues" />
<CheckBoxPreference android:title=""
android:summary="Include Aerodrome Notams"
android:defaultValue="false" android:key="filterIncludeAerodrome" />
<CheckBoxPreference android:title=""
android:summary="Delete night-time Notams"
android:defaultValue="true" android:key="filterDeleteNighttime" />
<ListPreference android:title="Select category to change"
android:summary="Set to: Airspace organisation"
android:key="filterCategory"
android:defaultValue="0"
android:entries="#array/filterCategoryOptions"
android:entryValues="#array/filterCategoryValues" />
<Preference android:title="Show filters for category"
android:summary="Click to choose subjects to delete"
android:key="filterShow" />
</PreferenceScreen>
</PreferenceCategory>
The contents of "Show filters for category" will depend on the "Filter type" and "Select category to change" settings.
This is the simple test code I have for the "Show filters" click listener (cut down just to show essentials):
public class Settings extends PreferenceActivity
implements OnSharedPreferenceChangeListener
{
------
public static final String KEY_FILTER_SHOW = "filterShow";
------
private Preference mFilterShow;
------
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.layout.settings);
// Get a reference to the preferences
------
mFilterShow = (Preference)findPreference(KEY_FILTER_SHOW);
------
// Set the click listener for Show Filter options
mFilterShow.setOnPreferenceClickListener(new OnPreferenceClickListener()
{
public boolean onPreferenceClick(Preference pref)
{
Context ctx = pref.getContext();
PreferenceScreen screen =
pref.getPreferenceManager().createPreferenceScreen(ctx);
CheckBoxPreference cb1 = new CheckBoxPreference(ctx);
cb1.setTitle("This is cb1");
cb1.setKey("cb1_key");
cb1.setDefaultValue(false);
screen.addPreference(cb1);
return true;
}
});
OK, I have solved the problem myself, through a process of iteration! Others might find this useful.
Just create an empty PreferenceScreen in the xml:
<PreferenceScreen android:title="Show filters for category"
android:summary="Click to choose subjects to delete"
android:key="filterShow">
</PreferenceScreen>
Then in the code there is no need for the onClick listener - the contents of the screen are created in the onCreate function. Actually, since the contents of the screen need to change when the choice made in the Category list preference (see original code) changes, this needs to go in a separate function which is called both from onCreate and onSharedPreferenceChanged:
public static final String KEY_FILTER_SHOW = "filterShow";
...
private PreferenceScreen mFilterShow;
...
// In onCreate:
// Get a reference to the PreferenceScreen
mFilterShow =
(PreferenceScreen)getPreferenceScreen().findPreference(KEY_FILTER_SHOW);
// Now the code to create the contents of the screen
mFilterShow.removeAll();
CheckBoxPreference cb1 = new CheckBoxPreference(this);
cb1.setTitle("This is cb1");
cb1.setKey("cb1_key");
cb1.setDefaultValue(true);
mFilterShow.addPreference(cb1);
The above is just "proof of concept". It works exactly as you would expect. In my final version, I will create an array of CheckBoxPreferences with 'new' initially, then re-use them (changing title and default) when setting up the contents of the screen for each Category choice as it changes. The number of check boxes required may be different for each category - I will create an array for the maximum number required, then add as many as I need in each case.
I have two preference xml files. The first one (pref2.xml) contains 2 preferences:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="key"
android:title="title"
android:defaultValue="false"
/>
<CheckBoxPreference
android:key="key2"
android:title="title"
android:defaultValue="false"
/>
</PreferenceScreen>
and the other one (pref1.xml) contains 1 preference:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:key="key"
android:title="title"
android:defaultValue="false"
/>
</PreferenceScreen>
in my preference activity I am trying to change them:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref1);
this.getPreferenceScreen().removeAll();
addPreferencesFromResource(R.xml.pref2);
final ListAdapter adapter = getPreferenceScreen().getRootAdapter();
Log.d("LOG", "size of sharedPreferences"+adapter.getCount()+"(should be 2)");
actually here i get the right output and everything is displayed correctly. But I want to change the displayed preferences concerning one preference. Therefore I implemented the OnSharedPreferenceChangeListener in the preference activity:
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
super.onSharedPreferenceChanged(sharedPreferences, key);
//switch the widget type
if (key.equals("key")){
this.getPreferenceScreen().removeAll();
addPreferencesFromResource(R.xml.pref1);
final ListAdapter adapter = getPreferenceScreen().getRootAdapter();
Log.d("LOG", "size of sharedPreferences "+adapter.getCount()+" (should be 1)");
}
}
Well, the pref1 preferences are displayed correctly, but the output of
"size of sharedPreferences 2"
indicated that in the background there are still the old preferences applied. If i iterate over the listAdapter i get also the old preferences.
Any idea how I could solve this?
I found out that the listadapter is some how outdated. If I get the count of items via getPreferenceScreen().getPreferenceCount() I get the right amount. But how do I access these preferences ?
I'm fairly sure that problem lies with your having two preferences with a key of "key" even though they are on different screens. A preference is identified by its key and this needs to be unique to avoid conflicts. The listener only knows which preference is being changed from the key. I would change the keys to have unique values.
EDIT: Well, wasn't right :S
...
Okey, I finally found the solution. After changing the PreferenceScreen I need to bind manually the listView again:
getPreferenceScreen().bind((ListView)findViewById(android.R.id.list));
Hello fellow programmers, I have a little problem with Preferences activity.
http://developer.android.com/reference/android/preference/PreferenceActivity.html
I've got just one preference category and a listPreference:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceCategory android:title="#string/basic_settings" >
<ListPreference
android:defaultValue="70"
android:entries="#array/listArray"
android:entryValues="#array/listValues"
android:key="updates_interval"
android:persistent="true"
android:summary="#string/SOME_SUMMARY"
android:title="#string/SOME_TITLE" />
</PreferenceCategory>
I need to have the selected value (the default one or the user defined one) written in the summary of the listPreference, for example:
We will have at least 70 characters.
How can I do this from the code?
Any help is appreciated
Try like this..
Preference customPref = (Preference) findPreference("updates_interval");<-- your preferences key
customPref.setSummary("desired string");
here is a short example:
Preference etp = (Preference) findPreference("the_pref_key");
etp.setSummary("New summary");
This requires that you display your preferences either from a PreferenceActivity or from a PreferenceFragment, since findPreference() is a method of these classes. You most likely do that already.
To change the summary every time the user changes the actual preference, use a OnPreferenceChangeListener and check if the relevant key changed in the callback. After it has changed, just edit the summary like above.
You can create a subclass of ListPreference in which you set an OnPreferenceChangedListener from which you will have access to the new value, and set the text on your ListPreference. I think the setSummary() function on the ListPreference will update the text under the name of the preference. If that doesn't work you can also override getView() to implement your own custom view for the Preference on which you can set the text directly.
Is it somehow possible to include one preferences.xml into another, like it can be done for layouts with the <include /> tag?
Let's say:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceScreen
android:title="#string/pref_group_title_visual">
<include
preferences_filename="xml/pref_visual"/>
</PreferenceScreen>
...
Solution here it is to inflate both preference files from PreferencesActivity. For example:
addPreferencesFromResource(R.xml.options);
addPreferencesFromResource(R.xml.additional_options);
The solution soul shows works. It can be expanded to only show preferences if you're the developer using an unsigned version of the app ;)
addPreferencesFromResource(R.xml.options);
addPreferencesFromResource(R.xml.additional_options);
if (BuildConfig.DEBUG) {
addPreferencesFromResource(R.xml.developer_options);
}
I created a blog post regarding this issue and have a complete working code example available for download.
http://androidfu.blogspot.com/2012/05/developer-debug-with-nested-preferences.html
To truly achieve the nesting effect you can use this technique to relocate the loaded preferences to a group already loaded.
PreferenceCategory notifications = (PreferenceCategory) getPreferenceScreen ().findPreference (PreferenceKey.pref_notifications.name ());
addPreferencesFromResource (R.xml.pref_notifications, notifications);
Where the enhanced addPreferencesFromResource is defined as:
private void addPreferencesFromResource (int id, PreferenceGroup newParent) {
PreferenceScreen screen = getPreferenceScreen ();
int last = screen.getPreferenceCount ();
addPreferencesFromResource (id);
while (screen.getPreferenceCount () > last) {
Preference p = screen.getPreference (last);
screen.removePreference (p); // decreases the preference count
newParent.addPreference (p);
}
}
It works for any PreferenceGroup such as PreferenceScreen and PreferenceCategory.
No, it seems to be impossible. But there's a simple workaround. You can make another PreferenceActivity that loads nested PreferenceScreen. And in the main preference.xml file you need to create a Preference object and set an Intent object for it in code (using setIntent() method). This Intent must be used to create the second PreferenceActivity.