Android Spinner's onItemSelected executed twice when going back to Fragment

你离开我真会死。 提交于 2019-12-23 09:08:03

问题


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);
}

回答1:


Use stateSpinner.setSelection(defaultState, false); in place of stateSpinner.setSelection(defaultState);




回答2:


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.




回答3:


Add condition view!=null in ItemSelectedListener like this:

spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                    @Override
                    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

                        if(view!=null)
                        {//write your code
                        }
                    }

                    @Override
                    public void onNothingSelected(AdapterView<?> parent) {

                    }
                });


来源:https://stackoverflow.com/questions/30253238/android-spinners-onitemselected-executed-twice-when-going-back-to-fragment

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!