Search code examples
androidsharedpreferencesandroid-preferencespreferenceactivityandroid-sharedpreferences

How to check input in PreferenceActivity and prevent storing of invalid values?


I have prepared a complete and simple test case for my question: ValidatePrefs app at GitHub:

app screenshots

When you click the "Settings" icon in the top right corner, SettingsActivity is displayed.

I would like to validate the 3 EditTextPreference fields by returning true or false from the onPreferenceChange method, but it is never called:

public class SettingsActivity extends PreferenceActivity implements Preference.OnPreferenceChangeListener {
    private static final String TAG = SettingsActivity.class.getSimpleName();

    public static final String ADDRESS   = "address";
    public static final String USERNAME  = "username";
    public static final String PASSWORD  = "password";

    @Override
    public void onCreate(Bundle savedInstanceBundle) {
        super.onCreate(savedInstanceBundle);
        addPreferencesFromResource(R.xml.settings);
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object value) {    
        if (! (preference instanceof EditTextPreference)) {
            return false;
        }

        EditTextPreference editTextPreference = (EditTextPreference)preference;
        String key = editTextPreference.getKey();
        String text = editTextPreference.getText();

        if (key == null || key.isEmpty() || text == null || text.isEmpty()) {
            return false;
        }

        switch (key) {
            case ADDRESS: {
                try {
                    new URI(text);
                } catch (URISyntaxException ex) {
                    ex.printStackTrace();
                    return false;
                }
                return true;
            }

            case USERNAME: {
                return text.length() > 0;
            }

            case PASSWORD: {
                return text.length() > 0;
            }
        }

        return false;
    }
}

UPDATE:

After adding findPreference and setOnPreferenceChangeListener calls in the SettingsActivity the method onPreferenceChange is finally called:

@Override
public void onCreate(Bundle savedInstanceBundle) {
    super.onCreate(savedInstanceBundle);
    addPreferencesFromResource(R.xml.settings);

    EditTextPreference address = (EditTextPreference) findPreference(ADDRESS);
    EditTextPreference username = (EditTextPreference) findPreference(USERNAME);
    EditTextPreference password = (EditTextPreference) findPreference(PASSWORD);

    address.setOnPreferenceChangeListener(this);
    username.setOnPreferenceChangeListener(this);
    password.setOnPreferenceChangeListener(this);
}

However I still can not validate and prevent saving wrong data, because the text variable contains the old value.

You can see it in the debugger screenshot below - I enter the new (and invalid) value of an empty string, but the variable text still contains the old value of user1:

debugger

UPDATE 2:

Okay, I was wrongly inspecting the old value stored in Preference, I should have looked at the new value, passed as 2nd argument to onPreferenceChange method. Here the fixed version of the method in my SettingsActivity:

@Override
public boolean onPreferenceChange(Preference preference, Object obj) {
    if (!(preference instanceof EditTextPreference && obj instanceof String)) {
        return false;
    }

    EditTextPreference editTextPreference = (EditTextPreference)preference;
    String key = editTextPreference.getKey();
    String oldValue = editTextPreference.getText();
    String newValue = String.valueOf(obj);

    Log.d(TAG, String.format("key %s, value %s -> %s", key, oldValue, newValue));

    // TODO validate the newValue and return true or false

Solution

  • However that method is never called.

    It seems to me you have forgotten to register setOnPreferenceChangeListener(), that's why the callback is not called.