I am new to Android, and having some trouble with Spinners in a DialogFragment.
I am trying to create a dialog fragment with two spinners, both populated with data from string array resources.
I'm not getting any errors, and when stepping through with the debugger I can see that after the appropriate methods are called, the Spinners contain Adapters which contain the data from the arrays.
However when the dialog is opened the spinners always display as empty.
I've Spent hours scanning my code for errors and pouring over documentation, and looking at related posts.
Other cases of empty spinners like the one found here Spinner wont show dropdown in fragment and here Spinner appears empty but contains data seem to be caused by problems with the setup code for the spinner, but I can't find anything like that here.
I thought it might have something to do with View Binding, so I tried using findViewById() to get my references for the Views instead, but that didn't work.
I'm wondering if it could be an issue specific to Fragment or DialogFragment since I'm not experiencing this in Activity.
I'm stuck and I would appreciate any guidance anyone can offer!
Dialog Fragment:
'''
public class AddGoalDialog extends DialogFragment {
FragmentAddGoalDialogBinding binding;
public AddGoalDialog() {
// Required empty public constructor
}
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState){
return new AlertDialog.Builder(requireContext())
.setTitle(getString(R.string.new_goal_dialog_title))
.setPositiveButton(getString(R.string.submit), (dialog, id) -> {
doPositiveClick();
} )
.setNegativeButton(getString(R.string.cancel), (dialog, id) -> {
dialog.cancel();
})
.setView(R.layout.fragment_add_goal_dialog)
.create();
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
binding = FragmentAddGoalDialogBinding.bind(view);
ArrayAdapter<CharSequence> durAdapter = ArrayAdapter.createFromResource(getContext(),
R.array.goal_duration_array, android.R.layout.simple_spinner_item);
durAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Spinner dialogSpinnerGoalDuration = view.findViewById(R.id.dialog_spinner_goal_duration);
dialogSpinnerGoalDuration.setAdapter(durAdapter);
ArrayAdapter<CharSequence> typeAdapter = ArrayAdapter.createFromResource(getContext(),
R.array.goal_type_array, android.R.layout.simple_spinner_item);
typeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Spinner dialogSpinnerGoalType = binding.dialogSpinnerGoalType;
dialogSpinnerGoalType.setAdapter(typeAdapter);
super.onViewCreated(view, savedInstanceState);
}
}
'''
Dialog Fragment Layout:
'''
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
tools:context=".AddGoalDialog">
<Spinner
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/spinner_goal_duration"/>
<Spinner
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/spinner_goal_type"/>
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editText_enter_goal"
android:inputType="number"
android:hint="@string/enter_a_goal"/>
</LinearLayout>
'''
There were two problems with my code that were causing this issue.
I found the solution to the first problem in the DialogFragment documentation.
"onViewCreated() is never called on a custom DialogFragment unless you've overridden onCreateView() and provided a non-null view." https://developer.android.com/guide/fragments/dialogs#java.
I had put all the setup code for the spinners in the onViewCreated() method. Although I had also tried putting it in the onCreateDialog() method, at that type I had improperly set up view binding.
The solution was to move the setup code for the spinners to the onViewCreated() method and set up view binding as described here How to correctly use Android View Binding in DialogFragment?.
@NonNull
@Override
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState){
binding = FragmentAddGoalDialogBinding.inflate(LayoutInflater.from(getContext()));
ArrayAdapter<CharSequence> durAdapter = ArrayAdapter.createFromResource(getContext(),
R.array.goal_duration_array, android.R.layout.simple_spinner_item);
durAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Spinner dialogSpinnerGoalDuration = binding.dialogSpinnerGoalDuration;
dialogSpinnerGoalDuration.setAdapter(durAdapter);
ArrayAdapter<CharSequence> typeAdapter = ArrayAdapter.createFromResource(getContext(),
R.array.goal_type_array, android.R.layout.simple_spinner_item);
typeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
Spinner dialogSpinnerGoalType = binding.dialogSpinnerGoalType;
dialogSpinnerGoalType.setAdapter(typeAdapter);
return new AlertDialog.Builder(requireContext())
.setTitle(getString(R.string.new_goal_dialog_title))
.setPositiveButton(getString(R.string.submit), (dialog, id) -> {
doPositiveClick();
} )
.setNegativeButton(getString(R.string.cancel), (dialog, id) -> {
dialog.cancel();
})
.setView(binding.getRoot())
.create();;
}