Why does Android ignore OnPreferenceClickListener() that returns true?

1.5k Views Asked by At

I defined my preferences in xml file like the following:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceScreen
    android:title="@string/pref_screen"
    android:key="pref_screen_key">

    <CheckBoxPreference
        android:defaultValue="true"
        android:key="prefs1_key"
        android:title="@string/prefs1_str"
        android:summary="@string/prefs1_summary" />
        ....

Inside PreferenceActivity I override onPreferenceClick() for "pref_screen_key":

     ...
     findPreference("pref_screen_key").setOnPreferenceClickListener(
     new OnPreferenceClickListener() {

     @Override
     public boolean onPreferenceClick(Preference preference) {
         if (flag) {
              // do some stuff
              return true; // According to Android doc it means, that click was handled
          } else
              return false;
     }

So I wish that Android will not open view with CheckBoxPreference if my flag is true, but just executes my stuff (I return true inside onPreferenceClick() to indicate that the click was handled and it is not needed to execute the default onPreferenceClick() behavior). Unfortunately, Android always handles onPreferenceClick() with default behavior and makes my stuff at the same time.

Is it a bug in Android? Is there a way to prevent Android from showing CheckBoxPreference after user clicks on PreferenceScreen?

4

There are 4 best solutions below

0
On BEST ANSWER

You're probably running into problems with the fact that the flag must be declared final to be accessed inside the OnPreferenceClickListener. Try encapsulating it in a class and declaring the class final.

To more directly answer your question, remember that when you return true from onPreferenceClick(), you're telling the system "don't worry, I handled it." So, when you simply return true without actually doing anything, the system isn't ignoring you, per se, you just told it to do nothing when the Preference is clicked.

Your code looks similar to lines 108-115 of this example. Look through that and it may help.

0
On

The bug is in https://github.com/android/platform_frameworks_base/blob/android-5.1.1_r13/core/java/android/preference/Preference.java#L985

In Preference.performClick, it checks if isEnabled() is true, calls onClick(), then your listener and returns if it returns false - if not, continue processing, and propagate the click to the right tree / screen / start the activity specified.

The bug is that it calls onClick before your onPreferenceClick, so checkboxes for example are always toggled, no matter what your onPreferenceClick returns.

Workaround: unfortunately, you'll need to subclass all preferences and do your own listener dispatching and only call super.onClick() if allowed.

0
On

I believe you want to use setOnPreferenceChangeListener instead of setOnPreferenceClickListener. As per the android docs:

This is called before the state of the Preference is about to be updated and before the state is persisted.

Return:

True to update the state of the Preference with the new value.

Example:

Preference pref = findPreference("pref_key");
pref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
  @Override
  public boolean onPreferenceChange(Preference preference, Object newValue) {
    if (flag) {
      // do some stuff
      return false; // Pref change will be not be persisted.
    } else {
      return true;
    }
  }
});
0
On

I use getActivity().recreate() to interrupt onClick().

...
findPreference("pref_screen_key").setOnPreferenceClickListener(
new OnPreferenceClickListener() {

@Override
public boolean onPreferenceClick(Preference preference) {
    if (flag) {
         // do some stuff
         getActivity().recreate()
         return true; // According to Android doc it means, that click was handled
     } else
         return false;
}

Or it may be getActivity().onBackPressed() or getActivity().finish() depending on the circumstances.