I am building a Preference Activity where most of the preferences in the list will be executing code and not modifying a SharedPreference directly. My preferences.xml file looks like this.
<PreferenceCategory
android:title="Connection" >
<Preference
android:id="#+id/settings_connectToNewComputer"
android:key="connectToNewComputer"
android:summary="Currently connected to:"
android:title="Connect to new computer" />
<Preference
android:id="#+id/removeDevice"
android:key="removeDevice"
android:summary="Remove this device from the computer's whitelist"
android:title="Remove this device from computer" />
</PreferenceCategory>
<PreferenceCategory
android:title="About" >
<Preference
android:id="#+id/settings_About"
android:key="about"
android:summary="About me and my thanks to those who made this app great"
android:title="About Hue Pro" />
<Preference
android:id="#+id/contact"
android:key="contact"
android:summary="Contact me with comments, bugs, and suggestions for updates"
android:title="Contact me" />
</PreferenceCategory>
My goal is to have a block of code executed when a one of these preferences are clicked. Similar to the "Clear search history" in the Google Play settings preference menu. (http://i.imgur.com/qnHbJX9.png)
Does anyone know how to make this possible?
I have to add that I have tried using findPreference("KeyNameHere") but it always returns null.
Thank you!
Edit:
I added in this code and implemented OnPreferenceClickListener:
#Override
public boolean onPreferenceClick(Preference preference) {
return false;
}
But this method never gets called. Is there another way to do this?
Edit 2:
I have found that if I take out the PreferenceCategory tags so I am left with this:
<Preference
android:id="#+id/settings_connectToNewComputer"
android:key="connectToNewComputer"
android:summary="Currently connected to:"
android:title="Connect to new computer" />
<Preference
android:id="#+id/removeDevice"
android:key="removeDevice"
android:summary="Remove this device from the computer's whitelist"
android:title="Remove this device from computer" />
<Preference
android:id="#+id/settings_About"
android:key="about"
android:summary="About me and my thanks to those who made this app great"
android:title="About Hue Pro" />
<Preference
android:id="#+id/contact"
android:key="contact"
android:summary="Contact me with comments, bugs, and suggestions for updates"
android:title="Contact me" />
and call this:
getPreferenceScreen().setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
return false;
}
});
then I actually get a response from the click event. The only down side is I have to remove the preference grouping. Anyone know why this is and any way to fix it?
Implement OnPreferenceClickListener and in the onPreferenceClick
#Override
public boolean onPreferenceClick (Preference preference)
{
String key = preference.getKey();
// do what ever you want with this key
}
Maybe this could not be useful for OP, but could be useful for someone else.
I'd like to write a sort of summary; in general, you can follow mainly three ways:
1) you can find your preference somewhere in your code with
Preference examplePreference = findPreference(KEY_EXAMPLE_PREFERENCE);
and then you can add a click listener and override its on click method with
examplePreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
// handle click here
}
});
This has to be done for every preference whose clicks you want to listen to
2) You can implement Preference.OnPreferenceClickListener interface in your settings fragment/activity and override onPreferenceClick just once, by using a switch construct or a if-else if-else if-... construct and merging all the single handlings; it should be something like:
#Override
public boolean onPreferenceClick(Preference preference) {
switch (preference.getKey()) {
case KEY_EXAMPLE_PREFERENCE: {
// handle click here
}
break;
case ...
}
}
Then, you still have to find each preference but you can simply call on each of them
setOnPreferenceClickListener(this);
(I think the OP's implementation didn't work (his method wasn't called) because of this last part)
we pass "this" as parameter because we implemented the click listener interface
3) (which I think is the easiest) you can override
onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference)
in your preference fragment/activity without implementing any other interface and there you can copy the switch of the if-else if-... construct of option 2); the main advantage in that you shouldn't need to find each preference and to call on them setOnPreferenceClickListener.
Hope this will be useful for someone!
Just override:
#Override
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) {
String key = preference.getKey();
...
return super.onPreferenceTreeClick(preferenceScreen, preference);
}
You could also find the preference and set the click listener.
Preference connectToNewComputer= findPreference("connectToNewComputer");
connectToNewComputer.setOnPreferenceClickListener(this);
For Androidx in Feb 2020
Others answers were not worked in Androidx for me. I implemented Settings from Android Developers guides
See below guide for implementing click listener
1) Implement PreferenceManager.OnPreferenceTreeClickListener in your settings fragment, like below code
import androidx.preference.PreferenceManager;
class SettingsFragment extends PreferenceFragmentCompat implements PreferenceManager.OnPreferenceTreeClickListener {
2) Override onPreferenceTreeClick inside your SettingsFragment
#Override
public boolean onPreferenceTreeClick(Preference preference) {
String key = preference.getKey();
switch (key) {
case "key1":
return true;
case "key2":
return true;
//codes
}
}
I came up with my own (what I believe is really messed up) solution; but it works.
for(int x = 0; x < getPreferenceScreen().getPreferenceCount(); x++){
PreferenceCategory lol = (PreferenceCategory) getPreferenceScreen().getPreference(x);
for(int y = 0; y < lol.getPreferenceCount(); y++){
Preference pref = lol.getPreference(y);
pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener(){
#Override
public boolean onPreferenceClick(Preference preference) {
return false;
}
});
}
}
So what I have learned is there is a hierarchical system that works like: PreferenceScreen has children PreferenceCategory has children Preference, as you can see in the XML file. My problem was I could not set the preferences' onClickListeners directly from the PreferenceScreen. So I made two for loops that will get down to each Preference and set an OnPreferenceClickListener for each and every one of them. Messy, but works finally.
Your Preference object wont get null if you will find followings
(copypasting from the project):
public class ImePreferences extends PreferenceActivity {
.....
#Override
protected boolean isValidFragment(String fragmentName) {
return Settings.class.getName().equals(fragmentName);
}
.....
public static class Settings extends InputMethodSettingsFragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setInputMethodSettingsCategoryTitle(R.string.language_selection_title);
setSubtypeEnablerTitle(R.string.select_language);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.ime_preferences);
Preference pLcl = getPreferenceScreen().findPreference(getResources().getString(
R.string.dictionary_button));
pLcl.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
// handle click here
l.a("this is the click");
return true;
}
});
if(pLcl != null)
l.a(6576);
}
}
.....
}
For Kotlin
your xml should look like this
<Preference
app:title="Contact me"
app:key="contact"/>
do not forget the key.
Then in your Settings Activity find this class
class SettingsFragment : PreferenceFragmentCompat()
and add this code
override fun onPreferenceTreeClick(preference: Preference): Boolean {
val key = preference.key
return super.onPreferenceTreeClick(preference)
}
When you are done your code should look like this
class SettingsFragment : PreferenceFragmentCompat() {
override fun onPreferenceTreeClick(preference: Preference): Boolean {
val key = preference.key
return super.onPreferenceTreeClick(preference)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.root_preferences, rootKey)
}
}
Related
The issue I am having is that the method findPreference is always returning null. I have checked multiple times whether the key (i.e. "pref_about") is correct, and it is.
public class SettingsFragment extends PreferenceFragmentCompat {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.preferences, rootKey);
initPreferences();
}
private void initPreferences() {
Preference myPref = findPreference("pref_about");
myPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
mListener.onFragmentInteraction(TAG, "btn_about");
return true;
}
});
}
The corresponding XML file is:
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<Preference android:title="About" android:key="pref_about "/>
</PreferenceScreen>
What am I doing wrong here?
Only issue which could cause this is if you use nested PreferenceScreens and each screen opens a fragment, the findPreference may fail because the nested fragment might not contain the preferences you look for with findPreference.
I have some preferences in my preference screen:
<PreferenceCategory
android:key="category"
android:summary="Category"
android:title="Category">
<Preference
android:key="pref1"
android:summary="desc"
android:title="Pref 1" />
<Preference
android:key="pref2"
android:summary="desc"
android:title="Pref 2" />
</PreferenceCategory>
Finding them in PreferenceActivity:
Preference pref1, pref2;
#Override
protected void onCreate(final Bundle savedInstanceState) {
pref1 = findPreference("pref1");
pref2 = findPreference("pref2");
}
And set some OnPreferenceClickListener to them. How do I correctly define which preference was clicked? I'd like to do it in case-switch style, but I cannot figure out which types should I use:
Preference.OnPreferenceClickListener listener = new Preference.OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
switch (???){ //I guess, here goes the "preference"?
case ???: //getting error with pref1 or pref2
}
return false;
}
}
If I put preference from onPreferenceClick in switch(), I will get errors with case.
You can get the corresponding preference like
#Override
public boolean onPreferenceClick (Preference preference)
{
String key = preference.getKey();
// do what ever you want with this key
}
ref: Preference Activity on Preference Click Listener
hope this helps :)
You can use the field key of Preference
public boolean onPreferenceClick(Preference preference) {
if (preference.getKey().equals("pref1")) {
... do something ...
} else if (preference.getKey().equals("pref2")) {
... do something ...
}
return true;
}
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 :)
My Preferences all trigger the onSharedPreferenceChanged event upon a change. It works for all preferences: Checkbox, List, custom, etc. But it won't be called if I select a ringtone from the RingtonePreference. I have this code:
<CheckBoxPreference android:title="#string/pref_notification"
android:defaultValue="true" android:summary="#string/pref_notification_summary"
android:key="prefNotification" />
<RingtonePreference android:title="#string/pref_ringtone"
android:key="prefRingtone"
android:summary="#string/pref_ringtone_summary" android:ringtoneType="all" />
<CheckBoxPreference android:title="#string/pref_vibrate"
android:defaultValue="true" android:summary="#string/pref_vibrate_summary"
android:key="prefVibrationOn" />
<ListPreference android:title="#string/pref_notification_interval"
android:summary="#string/pref_notification_interval_summary"
android:key="prefNotificationInterval" android:defaultValue="60"
android:entries="#array/prefs_interval" android:entryValues="#array/prefs_interval_values" />
And my class:
public class TimePrefsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
addPreferencesFromResource(R.layout.preferences);
Preference dbPref = (Preference) findPreference("prefDeleteDb");
dbPref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference)
{
showWipeDbDialog();
return true;
}
});
}
#Override
public void onResume() {
super.onResume();
prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.registerOnSharedPreferenceChangeListener(this);
toggleEnableList();
}
#Override
public void onPause() {
prefs.unregisterOnSharedPreferenceChangeListener(this);
super.onPause();
}
#Override
public void onSharedPreferenceChanged(SharedPreferences arg0, String arg1)
{
boolean enabled = toggleEnableList();
if (enabled)
{
OnBootReceiver.setAlarm(TimePrefsActivity.this);
}
else
{
OnBootReceiver.cancelAlarm(TimePrefsActivity.this);
}
}
}
All the preferences, except the RingtonePreference, reach method onSharedPreferenceChanged. Does anyone have an idea? Thanks.
I struggled with the same problem which seems to be a bug in the android system.
After debugging the code I noticed the listener is not added to our RingtonePreference listeners map, unlike other classes like ListPreference.
I opened a ticket, but for now I found a way to overcome it using OnPreferenceChangeListener.
My code sets the preference summary to the selected ringtone, you can use your logic instead.
First make your activity implement OnPreferenceChangeListener and write the onPreferenceChange method
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
updateRingtoneSummary((RingtonePreference) preference, Uri.parse((String) newValue));
return true;
}
private void updateRingtoneSummary(RingtonePreference preference, Uri ringtoneUri) {
Ringtone ringtone = RingtoneManager.getRingtone(this, ringtoneUri);
if (ringtone != null)
preference.setSummary(ringtone.getTitle(this));
else
preference.setSummary("Silent");
}
Notice that unlike onSharedPreferenceChanged, onPreferenceChange is called before the preference is updated, so you must use the newValue parameter to get the selected data instead of getting it from the preference.
Then, set the listener on OnResume:
#Override
protected void onResume() {
super.onResume();
// A patch to overcome OnSharedPreferenceChange not being called by RingtonePreference bug
RingtonePreference pref = (RingtonePreference) findPreference(getString(R.string.pref_ringtone));
pref.setOnPreferenceChangeListener(this);
}
Hope this helps.
I also thought this was a bug in the system at first, but the issue is actually more subtle. RingtonePreference launches a new activity via an intent. This means that your PreferenceActivity gets paused. And you're unregistering your listener in onPause(). If you don't do this, it'll work fine (at least it did for me).
But naturally, you can't have your handler stay registered forever. I compromised by using onStart()/onStop() instead of onResume()/onPause().
I had to manually set the OnPreferenceChangeListener myself on my SettingsFragment:
Preference notificationSoundPref = findPreference(Constants.PREFS_NOTIFICATION_SOUND);
notificationSoundPref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
// do what you need here
return true;
}
});
I'm making a backup and restore options in my android app. Then you open the preference I want a button to backup and a button to restore.
I make the button in my xml/preference.xml file like this:
<PreferenceCategory android:title="Backup">
<Preference
android:key="backup"
android:title="Backup"
android:summary="Make a backup of shows"
/>
<Preference
android:key="restore"
android:title="Restore"
android:summary="Restore shows from backup"
/>
</PreferenceCategory>
I my preference class I implements OnSharedPreferenceChangeListener, and add getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); to onResume() and getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); to OnPause().
The i implements onSharedPreferenceChanged:
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
// Let's do something when my counter preference value changes
if (key.equals("backup")) {
Toast.makeText(this, "Backup button pressed", Toast.LENGTH_SHORT).show();
} else if (key.equals("restore")) {
Toast.makeText(this, "Restore button pressed", Toast.LENGTH_SHORT).show();
}
}
But no toast is displayed then i press one of the buttons. I works fine on i.e. CheckBoxPreference, but i only need a button, not the checkbox. Some one who can help?
If it is just a simple button then there is no preference that can be changed, so your onSharedPreferenceChanged will not be called in this case.
Use an OnClick listener instead:
OnPreferenceClickListener btnListener = new OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
final String key = preference.getKey();
if (key.equals("backup")) {
// show toast
return true; // we handled the click
}
return false; // we didn't handle the click
}
};
Preference prefBtn = findPreference("backup");
prefBtn.setOnPreferenceClickListener(btnListener);
put your code to
public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen,
Preference preference);
method. preference here is the preference that were clicked.