Custom ListPreference with dynamic entries

Go To StackoverFlow.com

6

I need dynamic entries in ListPreference so I can not use conventional way of XML setup of which there are tons of materials online. So far I have following setup as you can see bellow. Problem is that when I run this I see dialog with title and message but no entries are showed even though I know that entries and values are not empty (I know that my entries and values are same but I would get error if I didn't supplied entries)


my.preference.DynamicPreference
            android:title="@string/date_format"
            android:dialogMessage="@string/profile_info_date_format"
            android:entryValues="@array/date_format_values"
            android:entries="@array/date_format_values"

public class DynamicPreference extends ListPreference {
    private int index;

    public DynamicPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DynamicPreference(Context context) {
        super(context);
    }

    @Override
    protected void onPrepareDialogBuilder(AlertDialog.Builder builder) {
        builder.setTitle(getTitle());
        builder.setMessage(getDialogMessage());
        builder.setSingleChoiceItems(entries(), -1, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialogInterface, int i) {

            }
        });
        super.onPrepareDialogBuilder(builder);
    }

    @Override
    public void setEntries(CharSequence[] sequence) {
        CharSequence[] entries = listObjects().toArray(new CharSequence[listObjects().size()]);
        super.setEntries(entries);
    }

    @Override
    public void setEntryValues(CharSequence[] sequence) {
        CharSequence[] values = getContext().getResources().getStringArray(R.string.date_format);
        super.setEntryValues(values);
    }
}
2012-04-05 19:21
by peter_budo


14

The android:dialogMessage was good starting point here, thank you @MH. for spotting it. Bellow is simple setup I ended with, I hope someone may find it helpful

<my.preference.DynamicPreference
        android:title="@string/local_time"
        android:key="profile_info_local_time"
        />

public class DynamicPreference extends ListPreference {


    public DynamicPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public DynamicPreference(Context context) {
        super(context);
    }

    @Override
    protected View onCreateDialogView() {
        ListView view = new ListView(getContext());
        view.setAdapter(adapter());
        setEntries(entries());
        setEntryValues(entryValues());
        setValueIndex(initializeIndex());
        return view;
    }

    private ListAdapter adapter() {
        return new ArrayAdapter(getContext(), android.R.layout.select_dialog_singlechoice);
    }

    private CharSequence[] entries() {
        //action to provide entry data in char sequence array for list
    }

    private CharSequence[] entryValues() {
        //action to provide value data for list
    }
}
2012-04-12 09:43
by peter_budo
Is this the only way to fill the ListPreference in a programmatic way - enzom83 2012-04-24 22:17
@enzom83 this is basic idea how to do it. I do not claim to be the best, but as far you can see there hasn't been any other posts in regards it. Are yo having some problems - peter_budo 2012-04-26 11:39
@peter_budo: There is no need to extend ListPreference, it is sufficient to set some initial values in onCreate() and then override the onPreferenceClick() handler for the specific object. Here is an example: http://stackoverflow.com/questions/6474707/how-to-fill-listpreference-dynamically-when-onpreferenceclick-is-triggere - ccpizza 2012-12-11 22:07
This has worked for me but it the dialog that appeared for selecting an option, there was a blank row at the bottom. I tried this another one: http://androidtechnicalblog.blogspot.com.es/2014/04/listpreference-how-to-load-data.html and it worked perfectly, no blank rows, and options loaded dinamically without any problem - user3289695 2016-06-04 21:08


3

I can see some potential possibilities for why it isn't working as expected:

  1. Where does listObjects come from? Its presence suggests it's a member variable, but I don't see it getting set or initialized anywhere. Check that your not using an 'empty' list to populate the dialog, as that might be causing the absence of any items in it.

  2. Alternatively, are you ever explicitly calling setEntries(...) and setEntryValues(...)? I'm asking, because ListPreference doesn't use those two setters internally - it directly uses the private member variables (mEntries and mEntryValues) for that. In other words, if you don't ever call both functions yourself, no one will, which means that the arrays will never get set on the super class either; hence the empty dialog.

  3. Similar to my first observation: what is entries()? It sitting in onPrepareDialogBuilder, but it does not seem to be declared anywhere.

Perhaps it's best to start adding some more code snippets, because based on everything that's missing, there's no way of telling where the exact origin of your problem lies...

Edit: Alright, I set up a quick test project to follow your steps. The solution to your problem is actually fairly straightforward: get rid of the android:dialogMessage attribute, and your list items should show up - I have to add that I only tested this with a plain ListPreference.

The problem is easily found if you go look at the source for ListPreference, with extends from DialogPreference. In ShowDialog() the following can be found:

285        View contentView = onCreateDialogView();
286        if (contentView != null) {
287            onBindDialogView(contentView);
288            mBuilder.setView(contentView);
289        } else {
290            mBuilder.setMessage(mDialogMessage);
291        }
292        
293        onPrepareDialogBuilder(mBuilder);

Now, as you can see it all depends on what onCreateDialog returns, because at the time onPrepareDialogBuilder is called, the decision what to display is already made. So let's have a look at that:

336    protected View onCreateDialogView() {
337        if (mDialogLayoutResId == 0) {
338            return null;
339        }
340        
341        LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
342                Context.LAYOUT_INFLATER_SERVICE);
343        return inflater.inflate(mDialogLayoutResId, null);
344    }

It appears it tries to inflate a resource referenced by mDialogLayoutResId. If that isn't set or available, it'll return null and only then the dialog 'message' will show. The content (list with items) will only show if there is a valid layout referenced. If you want both the content and the message to display, you will need to add a custom dialog layout using the android:dialogLayout attribute, and add a TextView with android:id="@android:id/message" as id. In the case of a ListPreference, the message will then be shown below the list, by default.

Note that you do not need to extend the built-in ListPreference in order to add entries and values programmatically. Simple call setEntries(...) and setEntryValues(...) on the ListPreference instance with the data you want it to show.

Also, in the case of your DynamicPreference subclass, any behaviour you changed may get overridden as you call super.onPrepareDialogBuilder(builder) all the way at the end of your method. As mentioned earlier though: I've just tested this with the default ListPreference and that seems to work fine and do everything you request.

2012-04-05 21:22
by MH.
1) Part of the code that I did not posted, but I can assure you that it does return array as expected. 2) Nope not calling them anywhere, seems like I may misunderstand they usage. 3) As in first case, part of code that I did not post and again it does return valid objec - peter_budo 2012-04-05 23:00
Please have a look at the edit in my answer for both the cause of your problem and the solution. Turns out you don't need to subclass ListPreference. : - MH. 2012-04-06 00:21
Yes, this does work without that attribute. Other classes extending DialogPreference I so far used had no problem with it. I did small search and it seems that xml attribute android:dialogMessage for ListPreference is on Android bug list http://code.google.com/p/android/issues/detail?id=449 - peter_budo 2012-04-07 08:01
Ads