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);
}
}
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
}
}
I can see some potential possibilities for why it isn't working as expected:
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With