I am not able to identify the issue with my code and it seems no one face this kind of issue, so not able to track this in stack overflow.
Exception message:
Caused by: java.lang.ClassCastException: android.preference.CheckBoxPreference cannot be cast to android.preference.SwitchPreference
Code:
private Preference preference;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
addPreferencesFromResource(R.xml.settings);
loadAllViews();
}
private void loadAllViews()
{
if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH)
{
preference = (SwitchPreference) findPreference("preference"); //Exception occurs here.
}
else
{
preference = (CheckBoxPreference) findPreference("preference");
}
}
__________________ __________________ __________________
settings.xml:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<CheckBoxPreference
android:key="preference"
android:title="yes_or_no" />
</PreferenceScreen>
Some one please help me to figure it out.
CheckBoxPreference does not extends SwitchPreference; hence it cannot be cast to it. Both of these classes are children of TwoStatePreference.
From your code, it seems that you are referencing one preference key for two different preference components:
if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH)
{
preference = (SwitchPreference) findPreference("preference"); //Exception occurs here.
}
else
{
preference = (CheckBoxPreference) findPreference("preference");
}
As you can see, this will work fine for the correct preference type, but it will throw a ClassCastException for the incorrect type. Make sure you are referencing the correct key for the correct TwoStatePreference.
<?xml version="1.0" encoding="utf-8"?>
<SwitchPreference
android:key="preference1"
android:title="yes_or_no" />
<CheckBoxPreference
android:key="preference2"
android:title="yes_or_no" />
In the code:
Preference preference;
if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH)
{
preference = (SwitchPreference) findPreference("preference1");
}
else
{
preference = (CheckBoxPreference) findPreference("preference2");
}
Need to have two separate layout.
One for check preference at layout directory.
And another for SwitchPreference at layout-v14 directory.
Related
I have a PreferenceScreen:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<CheckBoxPreference
android:id="#+id/checkBoxHighlightWeekends"
android:key="checkBoxHighlightWeekends"
android:summary="Weekends are different"
android:title="Highlight weekends" />
<MultiSelectListPreference
android:id="#+id/multiSelectListSelectWeekends"
android:key="multiSelectListSelectWeekends"
android:dialogTitle="Select weekends"
android:entries="#array/weekends"
android:entryValues="#array/weekends_values"
android:summary="Saturday, Sunday"
android:title="Select weekends"/>
</PreferenceScreen>
I'm trying to use only the "view" part of this and not make it write to it's default SharedPreferences. When user changes the preference, I manually check the changed data and send it to a MVVM repo, when then writes to my own custom SharedPreference. I plan to use LiveData to update the settings screen when it's opened. All this hassle because I'm trying to learn the MVVM architecture and Android in general.
Inside MainPreferenceFragment:
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings_main);
CheckBoxPreference checkBoxHighlightWeekends = getPreferenceManager().findPreference("checkBoxHighlightWeekends");
MultiSelectListPreference multiSelectListPreference = getPreferenceManager().findPreference("multiSelectListSelectWeekends");
checkBoxHighlightWeekends.setOnPreferenceChangeListener(changeListener);
multiSelectListPreference.setOnPreferenceChangeListener(changeListener);
}
Preference.OnPreferenceChangeListener changeListener = new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object o) {
// Call method in ViewModel which will save settings state to SharedPrefs
Logger.alert("Something changed! " + preference.getKey());
return true;
}
};
Any change to settings triggers the function, however the checkbox stops working - It doesn't change to the "tick" state anymore.
How can I strip out all the default click/change functionality from the PreferenceScreen and make it into a dumb view?
In this preferenceScreen the user unlinks the device from his account. At the moment I just have it as Unlink device, once the user clicks it, the unlinking happens.
But I would like to add a piece text like this:
Joe Foo's Device (joefoo#gmail.com) - Unlink Device
Hoe would I do this? I also need to add the user name dynamically from settingsActivity.
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<Preference android:title="#string/pref_title_advanced_unlink" >
<TextView somehow must be in here
android:id="#id/user_name_and_email" />
<intent android:action="android.intent.action.VIEW"
android:targetPackage="com.example.tvrplayer"
android:targetClass="com.example.tvrplayer.UnlinkActivity"
android.setflags="FLAG_ACTIVITY_CLEAR_TOP"/>
</Preference>
</PreferenceScreen>
preferences.xml
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory
android:key="pref_title_advanced"
android:title="Advanced" >
<CheckBoxPreference
android:defaultValue="false"
android:key="pref_title_advanced_link"
android:title="Link Device" />
</PreferenceCategory>
</PreferenceScreen>
PrefsActivity.java
private SharedPreferences mPreferences;
private SharedPreferences.OnSharedPreferenceChangeListener mPrefListener;
private CheckBoxPreference mCheckBoxPref;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
mCheckBoxPref = (CheckBoxPreference) getPreferenceScreen().findPreference(
"pref_title_advanced_link");
/*
* set initial summary as you desire. For example, userIdCurrent can be:
* "No Devices linked."
*/
mCheckBoxPref.setSummary(userIdCurrent);
mPrefListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs,
String key) {
if (key.equals("pref_title_advanced_link")) {
/*
* set post-click summary as you desire. For example,
* userIdPost can be:
* "Joe Foo's Device (joefoo#gmail.com)".
*/
mCheckBoxPref.setSummary(userIdPost);
}
}
};
mPreferences.registerOnSharedPreferenceChangeListener(mPrefListener);
}
Preferences have a subtitle called summary. Give your preference a key, then you can use findPreference(CharSequence key) in your PreferenceFragment to get a reference to your preference object, sort of like calling findViewById to get references to Views. Then call setSummary(int) or setSummary(CharSequence) on the preference object.
Alternatively, you could do something entirely more complex by providing a custom layout for your preference objects and/or subclass Preference and implement some custom data binding. But I think the above should do what you want.
I am struggling to restore the default values I specified in the preferences.xml, Here is my code:
Preference reset = findPreference(res.getString(R.string.DEFAULT_PREFS));
reset.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(Preferences.this);
sp.edit().clear().commit();
PreferenceManager.setDefaultValues(Preferences.this, R.layout.preferences, true);
return true;
}
});
This code is my understanding of the android's developers reference for the function setDefaultValues(context, resId, readAgain):
Parameters
context The context of the shared preferences.
resId The resource ID of the preference hierarchy XML file.
readAgain Whether to re-read the default values.
Note: this will NOT reset preferences back to their default values.
For that functionality, use getDefaultSharedPreferences(Context)
and clear it followed by a call to this method with
this parameter set to true.
Well, it does not work, the preferences values are the same after this code is executed.
Then I looked into the SharedPreferences variable sp, and it points to a system generated file in the path:
/data/data/<packagename>/shared_prefs/<packagename>_preferences.xml
which I can only assume is the same xml I provided when I created the activity.
addPreferencesFromResource(R.layout.preferences);
Also inspecting the sp variable, the hash table has all the preferences, but there is no field for default value.
EDIT:
Before I am asked to, here is an excerpt from the preferences.xml file
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<EditTextPreference
android:defaultValue="5000"
android:key="#string/MAX_MESSAGES"
android:numeric="integer"
android:summary="#string/MAX_MESSAGES_desc"
android:title="#string/MAX_MESSAGES_title" />
<EditTextPreference
android:defaultValue="10"
android:key="#string/VIEW_EDGE_ROWS"
android:numeric="integer"
android:summary="#string/VIEW_EDGE_ROWS_desc"
android:title="#string/VIEW_EDGE_ROWS_title" />
<ListPreference
android:defaultValue="0"
android:entries="#array/level_list"
android:entryValues="#array/level_values"
android:key="#string/INITIAL_ORG"
android:summary="#string/INITIAL_ORG_desc"
android:title="#string/INITIAL_ORG_title" />
<ListPreference
android:defaultValue="2"
android:entries="#array/view_list"
android:entryValues="#array/view_values"
android:key="#string/INITIAL_VIEW"
android:summary="#string/INITIAL_VIEW_desc"
android:title="#string/INITIAL_VIEW_title" />
<CheckBoxPreference
android:defaultValue="true"
android:key="#string/AUTOSCROLL"
android:summary="#string/AUTOSCROLL_desc"
android:title="#string/AUTOSCROLL_title" />
<CheckBoxPreference
android:defaultValue="true"
android:key="#string/SEND_THEN_EXIT"
android:summary="#string/SEND_THEN_EXIT_desc"
android:title="#string/SEND_THEN_EXIT_title" />
<Preference
android:key="#string/DEFAULT_PREFS"
android:summary="#string/DEFAULT_PREFS_desc"
android:title="#string/DEFAULT_PREFS_title" />
</PreferenceScreen>
This is my solution so far. After debugging into the Android source code I find out that setDefaultValues() is not reliable and does not work as intended (at least according to my expectations).
I restore the default values manually now. I have a map where I can fetch from the default values.
Here is an interesting note: Inspecting the Preference class shows it has a field called mDefaultValue which contains the default value for the preference. But this field can only be set by setDefaultValue() method, and there is no method to get it. It would have save me the need for a Map
This is the code I use now, tested and working:
Preference reset = findPreference(getResources().getString(R.string.DEFAULT_PREFS));
reset.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference p) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(Preferences.this);
SharedPreferences.Editor editor = sp.edit();
editor.clear();
// PreferenceManager.setDefaultValues(Preferences.this, R.layout.preferences, false);
for(int i = 0; i < getPreferenceScreen().getPreferenceCount(); i++) {
restoreDefault(editor, getPreferenceScreen().getPreference(i));
}
editor.commit();
return true;
}
}
private void restoreDefault(Editor editor, Preference p) {
if(p instanceof PreferenceCategory) {
PreferenceCategory pCat = (PreferenceCategory) p;
for(int i = 0; i < pCat.getPreferenceCount(); i++) {
restoreDefault(editor, pCat.getPreference(i));
}
}
if(p instanceof ListPreference) {
editor.putString(p.getKey(), resMap.get(p.getKey())._default);
}
if(p instanceof EditTextPreference) {
editor.putString(p.getKey(), resMap.get(p.getKey())._default);
}
if(p instanceof CheckBoxPreference) {
editor.putBoolean(p.getKey(), resMap.get(p.getKey())._default.equals("true"));
}
}
Another note: editor.commit() updates the preferences file, but does not update the preferences screen. You have to update each preference by using the listener (OnSharedPreferenceChangeListener()).
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);
I have the following PreferenceActivity defined:
public class HiddenPreferences extends PreferenceActivity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.hidden_prefs);
}
}
where the hidden_prefs.xml looks something like this:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<EditTextPreference android:key="testRestUrl"
android:title="REST service URI"
android:defaultValue="http://service/url">
</EditTextPreference>
</PreferenceScreen>
now I set the values to default and would like to read this preference in some other activity, like this:
PreferenceManager.setDefaultValues(this, R.xml.hidden_prefs, false);
prefs = PreferenceManager.getDefaultSharedPreferences(this);
but when calling:
prefs.getString("testRestUrl", "");
I need to give the default value as second parameter, and the call always returns "" (as given in the call) but not the default value as given in the XML android:defaultValue attribute.
How should the preference be access in order to get the default value?
I don't believe you can do this if you don't instantiate the PreferenceActivity.
Your best bet is to define a String in strings.xml or config.xml and use R.strings.testRestUrl in your code:
prefs.getString("testRestUrl", getString(R.string.testRestUrl));
and XML:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<EditTextPreference android:key="testRestUrl"
android:title="REST service URI"
android:defaultValue="R.string.testRestUrl">
</EditTextPreference>
</PreferenceScreen>