I created a spinner for my Fragment that populates it with data retrieved from an HTTP callout. When the Fragment is first created, I populate the spinner with its selection choices, set its setOnItemSelectedListener and set its initial selection in onCreateView().
stateSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
if (spinnerPosition != position)
{
spinnerPosition = position;
TextView stateSelected = (TextView) view;
String stateSelectedStr = stateSelected.getText().toString();
LinearLayout ballotsDisplay = (LinearLayout) getActivity().findViewById(R.id.ballotsDisplay);
ballotsDisplay.removeAllViews();
Map<String, String> calloutParams = new HashMap<String, String>();
calloutParams.put("state", stateSelectedStr);
// Create and execute AsyncTask to retrieve ballots
new RetrieveBallots().execute(calloutParams);
}
}
public void onNothingSelected(AdapterView<?> parent) {
return;
}
});
// Set default selection for spinner
int defaultState = adapter.getPosition(userState);
if (defaultState == -1)
{
defaultState = 0;
}
stateSpinner.setSelection(defaultState);
When the Fragment is created, everything works well, the spinner position is set to its default and the spinner item is selected once as shown in the log below:
5009-5009/com.project.test D/TEST﹕ onCreateView called
5009-5009/com.project.test D/TEST﹕ stateSpinner.setSelection
5009-5009/com.project.test D/TEST﹕ onActivityCreated called
5009-5009/com.project.test D/TEST﹕ onResume called
5009-5009/com.project.test D/TEST﹕ spinner item selected
The problem occurs when I navigate away from the Fragment to another fragment (I store the fragment onto backstack). When I click back to go back to my original Fragment, the spinner seems to have its item selected twice:
5009-5009/com.project.test D/TEST﹕ onCreateView called
5009-5009/com.project.test D/TEST﹕ stateSpinner.setSelection
5009-5009/com.project.test D/TEST﹕ onActivityCreated called
5009-5009/com.project.test D/TEST﹕ onResume called
5009-5009/com.project.test D/TEST﹕ spinner item selected
5009-5009/com.project.test D/TEST﹕ spinner item selected
So I have 2 questions:
1) Why does the spinner register 2 item selection occurrences when returning to it from the Back button.
2) Is there a fix to prevent 2 item selections from occurring? Right now the fragment is being populated with duplicate data since it retrieves the data twice.
** EDIT **
After changing to stateSpinner.setSelection(defaultState, false)
, I would get a null Pointer exception at ballotsDisplay.removeAllViews();
seems like ballotsDisplay is set to null for some reason with that change
stacktrace:
05-15 07:25:48.303 6153-6153/com.poliseewriters.polisee E/AndroidRuntime﹕ FATAL EXCEPTION: main java.lang.NullPointerException at com.polisee.ballotmeasures.BallotMeasuresFragment$1.onItemSelected(BallotMeasuresFragment.java:287) at android.widget.AdapterView.fireOnSelected(AdapterView.java:882) at android.widget.AdapterView.selectionChanged(AdapterView.java:865) at android.widget.AdapterView.checkSelectionChanged(AdapterView.java:1017) at android.widget.Spinner.layout(Spinner.java:363) at android.widget.AbsSpinner.setSelectionInt(AbsSpinner.java:292) at android.widget.AbsSpinner.setSelection(AbsSpinner.java:269) at com.polisee.ballotmeasures.BallotMeasuresFragment.setStateSpinner(BallotMeasuresFragment.java:314) at com.polisee.ballotmeasures.BallotMeasuresFragment.onCreateView(BallotMeasuresFragment.java:201) at android.support.v4.app.Fragment.performCreateView(Fragment.java:1786) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:953) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1136) at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:739) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1499) at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:456) at android.os.Handler.handleCallback(Handler.java:605) at android.os.Handler.dispatchMessage(Handler.java:92) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4441) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) at dalvik.system.NativeStart.main(Native Method)
** EDIT: Updated code to prevent onItemSelected from executing twice, needed to add null check for ballotsDisplay **
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
if (savedInstanceState != null) {
Log.d("TEST", "bundle = " + savedInstanceState.toString());
}
Log.d("TEST", "onCreateView called");
View view = (View) inflater.inflate(R.layout.fragment_ballot_measures, container, false);
setStateSpinner(view);
return view;
}
private void setStateSpinner(View view) {
try {
states = Utilities.getAllStateNames();
}
catch (Exception e) {
Log.e("Error", "Error retrieving names: " + e.getMessage());
}
Spinner stateSpinner = (Spinner) view.findViewById(R.id.stateSpinner);
final ArrayAdapter<String> adapter = new ArrayAdapter<String>(getActivity(), R.layout.ballotmeasures_state_spinner, states);
adapter.setDropDownViewResource(R.layout.ballotmeasures_state_spinner_dropdown);
stateSpinner.setAdapter(adapter);
stateSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
// Callback method to invoke when a state has been selected
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
Log.d("TEST", "spinner item selected");
TextView stateSelected = (TextView) view;
String stateSelectedStr = stateSelected.getText().toString();
// Remove all currently displayed views in the layout
LinearLayout ballotsDisplay = (LinearLayout) getActivity().findViewById(R.id.ballotsDisplay);
if (ballotsDisplay != null)
{
ballotsDisplay.removeAllViews();
}
Map<String, String> calloutParams = new HashMap<String, String>();
calloutParams.put("state", stateSelectedStr);
// AsyncTask to execute data retrieval
new RetrieveBallots().execute(calloutParams);
}
public void onNothingSelected(AdapterView<?> parent) {
return;
}
});
// Set default selection for spinner
int defaultState = adapter.getPosition(userState);
if (defaultState == -1)
{
defaultState = 0;
}
Log.d("TEST", "stateSpinner.setSelection");
stateSpinner.setSelection(defaultState, false);
}
Use stateSpinner.setSelection(defaultState, false);
in place of stateSpinner.setSelection(defaultState);
The problem is the onItemSelected()
callback gets called twice by Android Framework (maybe by design), the first time the view
parameter is null
, and the second time it is instantiated.
You cannot prevent 2 item selections from occurring, but you can check if the view
variable is null, if not, do the rest things.
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