39

I'm writing some custom preference dialogs in Android by extending the DialogPreference class. However, I'm getting a bit concerned at the amount of boiler plate code that is needed for this as there appears to be a lot of behaviour to test.

For instance, this example of a number preference dialog is fairly typical: http://svn.jimblackler.net/jimblackler/trunk/workspace/NewsWidget/src/net/jimblackler/newswidget/NumberPreference.java

In particular, the onSave()/RestoreInstanceState() methods and "class SavedState" parts, which are needed so that the current changes to the dialog are retained on orientation changes are quite verbose and complex.

Does anyone have any tips for writing DialogPreference classes in a more concise way?

gobernador
  • 5,659
  • 3
  • 32
  • 51
RichardNewton
  • 876
  • 1
  • 12
  • 20

1 Answers1

139

The bare minimum is:

  1. MyCustomDialogPreference(Context context, AttributeSet attrs) constructor.
    • Don't forget to call super(context, attrs).
    • Call setPersistent(false) to indicate to the super Preference class that you persist the preference value on your own.
    • If you want to inflate the dialog panel layout from a resource, then also call setDialogLayoutResource(int dialogLayoutResId).
  2. onBindDialogView(View view) - update the view with the value(s) of your preference.
    • Don't forget to call super.onBindDialogView(view).
  3. onDialogClosed(boolean positiveResult) - if positiveResult is true then persist the value(s) from your view to the SharedPreferences.
    • Don't forget to call super.onDialogClosed(positiveResult).

This was the bare minimum, and it assumes that:

  • Your custom DialogPreference manages a single preference key/value pair.
  • You are responsible for persisting the preference value.
  • You are inflating the dialog panel layout from a resource.

Now for some additional options:

(a) If you want to create the dialog panel layout programmatically, then implement also onCreateDialogView() instead of calling setDialogLayoutResource() in the constructor.

(b) If your preference supports only a single key/value pair, then you can use the helper save methods persistBoolean(boolean), persistFloat(float), persistInt(int), persistLong(long), persistString(String) when you persist the changed preference value in onDialogClosed(). Otherwise, you need to use the getEditor() method, like so:

private MyCustomView myView;

@Override
protected void onBindDialogView(View view) {
    super.onBindDialogView(view);

    // the view was created by my custom onCreateDialogView()
    myView = (MyCustomView)view;

    SharedPreferences sharedPreferences = getSharedPreferences();
    myView.setValue1(sharedPreferences.getString(myKey1, myDefaultValue1));
    myView.setValue2(sharedPreferences.getString(myKey2, myDefaultValue2));
}

@Override
protected void onDialogClosed(boolean positiveResult) {
    super.onDialogClosed(positiveResult);

    if (positiveResult) {
        Editor editor = getEditor();
        editor.putString(myKey1, myView.getValue1());
        editor.putString(myKey2, myView.getValue2());
        editor.commit();
    }
}

(c) If you plan to supply default values from an inflated xml, then you need to implement also the onGetDefaultValue(TypedArray a, int index) method.


@RichardNewton, I know that a month has passed since you asked the question. I hope you can still use it.

Roy Sharon
  • 3,488
  • 4
  • 24
  • 34
  • Oh, regarding the onSave/RestoreInstanceState methods: If your custom dialog panel doesn't have any state to persist, and you are handling the persisting of the preference value on your own, then there's no need to override the onSave/RestoreInstanceState methods. – Roy Sharon Jan 27 '11 at 06:08
  • Will persistBoolean and the other similar methods store the method with the key supplied to android:key? What if no key is supplied? – gsgx Dec 10 '12 at 22:54
  • Yes, it will persist using the supplied android:key. If no key is supplied it will throw `IllegalStateException("Preference does not have a key assigned.")` – Roy Sharon Dec 12 '12 at 17:05
  • 7
    You missed one thing: if you require default values, you need to implement `onSetInitialValue()`. Otherwise, both `setDefaultValue()` and `onGetDefaultValue()` will not persist the default value! – XåpplI'-I0llwlg'I - Jan 04 '13 at 18:33
  • Great post, thank you! One question though, you showed how to persist the value with the persist*() methods, but what about the reverse of this? In other words, how do you get the value of the preference -- for example during init so any field(s) in the dialog can be pre-populated? I see there's getSharedPreferences().getString() but takes a key and therefore implies that we know what the preference key will be, which may not be the case -- for example if the preference was added from XML (preferences.xml). – The Awnry Bear Apr 15 '13 at 02:21
  • I think I may have answered my own question. The preference's value can be retrieved by calling one of the getPersisted*() methods. So in your DialogPreference's init code, you could call getPersistedString("defaultValue") and use that value to pre-populate the dialog's field(s). – The Awnry Bear Apr 15 '13 at 03:26
  • Aside from completeness, there is no need to call `super.onDialogClosed(positiveResult)` because that method is empty. – tar Apr 28 '14 at 07:09
  • What is required to provide a proper summary that also reflects the current value? When do I have to call setSummary? – hotzen Sep 13 '14 at 13:07
  • @tar Is this specified that this method is going to always stay empty? No. So you have to call its super implementation. Perhaps new versions of Android will start doing something there. – Aleks N. Jan 27 '15 at 10:11
  • Great post, really. I didn't even need to open the SDK, just by reading this I was able to implement my own custom Dialog. – Raffaeu Jan 04 '16 at 11:05