2

I have a Floating Action Button in my layout. Users can choose the position of this button, left or right. This can be selected in the preferences.

The code to do this works OK, but a change in the preference is not detected by the listener.

If the app is restarted, the Floating Action Button is displayed according to the new preference, so I know the process with this preference works, but unfortunately the listener seems to fail.

What do I have to do to get the listener firing when the preference has changed?

Listener in my MainActivity:

private final SharedPreferences.OnSharedPreferenceChangeListener 
        mPositionFabListener = new SharedPreferences.OnSharedPreferenceChangeListener() {

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {

        Log.e(TAG,"Are we getting here?");
        // We do not get here when preference has changed. Why not??

        // Code to update Floating Action Button to new position

    }
};

I register the listener in the onResume() method of the MainActivity and unregister in the onPause().

@Override
protected void onResume() {
    super.onResume();
    PrefUtils.registerOnPrefChangeListener(mPositionFabListener);
}

@Override
protected void onPause() {
    PrefUtils.unregisterOnPrefChangeListener(mPositionFabListener);
    super.onPause();
}

The registerOnPrefChangeListener method is declared in a seperate class:

public class PrefUtils {

public static boolean getBoolean(String key, boolean defValue) {
    SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MainApplication.getContext());
    return settings.getBoolean(key, defValue);
}

public static void putBoolean(String key, boolean value) {
    SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(MainApplication.getContext()).edit();
    editor.putBoolean(key, value);
    editor.apply();
}

public static int getInt(String key, int defValue) {
    SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(MainApplication.getContext());
    return settings.getInt(key, defValue);
}

public static void putInt(String key, int value) {
    SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(MainApplication.getContext()).edit();
    editor.putInt(key, value);
    editor.apply();
}

public static void registerOnPrefChangeListener(OnSharedPreferenceChangeListener listener) {
    try {
        PreferenceManager.getDefaultSharedPreferences(MainApplication.getContext()).registerOnSharedPreferenceChangeListener(listener);
    } catch (Exception ignored) {}
}

public static void unregisterOnPrefChangeListener(OnSharedPreferenceChangeListener listener) {
    try {
        PreferenceManager.getDefaultSharedPreferences(MainApplication.getContext()).unregisterOnSharedPreferenceChangeListener(listener);
    } catch (Exception ignored) {}
}

}

UPDATE: In the GeneralPrefsFragment class I put in this listener for testing purposes. This listener is working. So why does it not work in the MainActivity?

public class GeneralPrefsFragment extends PreferenceFragment {


@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

   Preference  preference = findPreference(PrefUtils.POSITION_FLOATING_MENU_BUTTON);
   Preference.OnPreferenceChangeListener mListener = new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            PrefUtils.putBoolean(PrefUtils.POSITION_FLOATING_MENU_BUTTON, Boolean.TRUE.equals(newValue));

            PreferenceManager.getDefaultSharedPreferences(MainApplication.getContext()).edit().commit(); // to be sure all prefs are written

            Log.e(TAG, "The listener in " + TAG + " is listening");

            // This listener is fired as soon as changes in the preference are made!
            // Why is the same kind of listener not fired in the MainActivity?

            return true;
        }
    };
    preference.setOnPreferenceChangeListener(mListener);


}

}

SOLUTION: I got a fix. I still do not know why the former setup didn't work, but I got it working, thanks to the code in this answer.

In the MainAcivity's onCreate() method I placed the following listener and this one gets triggered when the preferences have changed.

SharedPreferences prefs =
        PreferenceManager.getDefaultSharedPreferences(this);

SharedPreferences.OnSharedPreferenceChangeListener mPrefsFabListener =
        new SharedPreferences.OnSharedPreferenceChangeListener() {
            public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
                if (PrefUtils.POSITION_FLOATING_MENU_BUTTON.equals(key)) {
                    FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
                    CoordinatorLayout.LayoutParams paramsFab = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
                    if (PrefUtils.getBoolean(PrefUtils.POSITION_FLOATING_MENU_BUTTON, false)) {
                        paramsFab.gravity = Gravity.BOTTOM | Gravity.START;
                    } else {
                        paramsFab.gravity = Gravity.BOTTOM | Gravity.END;
                    }
                }
            }
        };
prefs.registerOnSharedPreferenceChangeListener(mPrefsFabListener); 
Community
  • 1
  • 1
Paul Naveda
  • 724
  • 8
  • 16
  • Post the code in which you are editing the `SharedPreferences` please. – Giorgio Antonioli Apr 25 '17 at 19:51
  • In the posted code, you never have an update event that would fire your callback. Please [edit] the question to include the code that would invoke this. Voting to close for lack of context. – Matt Clark Apr 25 '17 at 20:01
  • @MattClark Why voting to close if I just ask a legitimate question? Please wait a minute. – Paul Naveda Apr 25 '17 at 20:06
  • As I said, _for lack of context_. If the question gets edited to include relevant details, I can retract my vote. – Matt Clark Apr 25 '17 at 20:09
  • @Matt Clark Thx. I'll do my best to update the question with the necessary information. – Paul Naveda Apr 25 '17 at 20:11
  • @MattClark I do not have more code. Maybe that is the problem? – Paul Naveda Apr 25 '17 at 20:18
  • And I assume that when you call something like `PrefUtils.putString("a", "b");` and you expect the callback to fire, correct? In PrefUtils, you throw away some exceptions - can you try and add log statements in these catches to validate you are not actually hitting an excpetion? – Matt Clark Apr 25 '17 at 20:18
  • @MattClark I ran the code with logging the possible exceptions, but there weren't any. I do not put a boolean when I change the preference. I assumed it would store the preference by just clicking it on the screen. I think it does, because the change gets saved. When I restart the app the new settings are visible. – Paul Naveda Apr 25 '17 at 20:29

1 Answers1

1

The OnSharedPreferenceChangeListener gets unregistered in the onPause() method of the MainAcitivity. That is a problem, because the MainActivity gets paused as soon as the General Preferences Activity is started in order to change the preferences. So, the listener is unregistered and therefore not listening right at the point where it is needed!

I removed the unregisterOnPrefChangeListener from the onPause() and put in the following code. This worked perfectly!

@Override
protected void onDestroy() {
    PrefUtils.unregisterOnPrefChangeListener(mPositionFabListener);
    super.onDestroy();
}
Paul Naveda
  • 724
  • 8
  • 16