屏幕旋转后多次调用Android微调器onItemSelected

时间:2015-01-02 17:20:15

标签: android android-spinner

我有一个带有三个微调器的布局。它们在下拉列表中显示的选项不同。
在我的onCreateView我有一个设置微调器的方法。在这个方法里面我有这样的东西:

  mySpinner = (Spinner) view.findViewById(R.id.my_spinner);
  ArrayAdapter<String> mySpinner =
            new ArrayAdapter<String>(getActivity(), R.layout.background,
                    new ArrayList<String>(Arrays.asList(getResources().getStringArray(R.array.spinner_one_data))));
  mySpinner.setDropDownViewResource(R.layout.spinner_text);
  mySpinner.setAdapter(mySpinner);
  mySpinner.setOnItemSelectedListener(this);

正如我所说,我的另外两个旋转器几乎相同,但有不同的选择。

我知道在{first setup'中为每个微调器调用onItemSelected一次,所以我有一个标志来防止这个问题。有了这个标志解决方案,我的微调器正在按预期工作。

问题是我在每个微调器中选择一个选项然后旋转屏幕。现在,onItemSelected被调用6次而不是我期待的3次(我设置了一个标志来管理3次调用的这种情况)。

为什么会发生这种情况?我应该怎样处理这个问题?

4 个答案:

答案 0 :(得分:28)

一般来说,我发现有许多不同的事件可以触发onItemSelected方法,很难跟踪所有这些事件。相反,我发现使用OnTouchListener仅响应用户启动的更改更简单。

为微调器创建监听器:

public class SpinnerInteractionListener implements AdapterView.OnItemSelectedListener, View.OnTouchListener {

    boolean userSelect = false;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        userSelect = true;
        return false;
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
        if (userSelect) { 
            // Your selection handling code here
            userSelect = false;
        }
    }

}

将侦听器作为OnItemSelectedListener和OnTouchListener添加到微调器:

SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);

答案 1 :(得分:1)

我找到了一个适合我的解决方案。

我有3个微调器,因此onItemSelected在初始微调器设置时调用3次。为避免onItemSelected在初始设置中触发方法,我创建了一个计数器,因此onItemSelected仅根据计数器值触发该方法。

我已经意识到,在我的情况下,如果旋转屏幕,onItemSelected会再次触发3次,加上每个微调器不在0位置的时间1}}。

一个例子:

我有3个微调器,用户将2更改为其中一个可用选项,然后位置0,这样他最终得到的情况如下:

First spinner - > Item 2 selected
Second spinner -> Item 0 selected (no changes)
Third spinner -> Item 1 selected

现在,如果我旋转屏幕,onItemSelected将针对初始微调器设置加3次,加上2次,对于位置0的微调器1}}。

@Override
public void onSaveInstanceState(Bundle outState) {
    int changedSpinners = 0;
    if (spinner1.getSelectedItemPosition() != 0) {
        changedSpinners += 1;
    }
    if (spinner2.getSelectedItemPosition() != 0) {
        changedSpinners += 1;
    }
    if (spinner3.getSelectedItemPosition() != 0) {
        changedSpinners += 1;
    }
    outState.putInt("changedSpinners", changedSpinners);
}

我已将状态保存在onSaveInstanceState中,然后在onCreateView我检查了savedInstanceState != null是否如此,如果是,则从捆绑中提取changedSpinners并更新我的反对采取相应行动。

答案 2 :(得分:0)

扩展Andres Q.的答案...如果您使用的是Java 8,则可以通过使用lambda表达式来使用更少的代码行来实现。此方法还放弃了创建单独的类以实现onTouchListener

的需要。
Boolean spinnerTouched; //declare this as an instance or class variable

spinnerTouched = false;
yourSpinner.setOnTouchListener((v,me) -> {spinnerTouched = true; v.performClick(); return false;});

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

        if(spinnerTouched){
            //do your stuff here
        }
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {
        //nothing selected
    }
});

答案 3 :(得分:0)

仅仅检查片段是否处于恢复状态怎么样?有这样的想法:

private AdapterView.OnItemSelectedListener mFilterListener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if (isResumed()) {
              //your code
            }
        }

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

        }
    };

@Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        //set mFilterListener
}

它消除了旋转问题和第一个设置问题。没有标志等。我在使用 TextWatchers 时遇到了同样的问题,并在评论中发现了这个 answer,这激发了我对这个解决方案的灵感。