【问题标题】:Android spinner onItemSelected called multiple times after screen rotation屏幕旋转后多次调用Android微调器onItemSelected
【发布时间】:2021-01-05 22:15:20
【问题描述】:

我有一个包含三个微调器的布局。它们在下拉菜单中显示的选项不同。
在我的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);

正如我所说,我的其他两个微调器几乎相同,但选项不同。

我知道 onItemSelected 在“第一次设置”中为每个微调器调用一次,所以我有一个标志来防止这个问题。使用此标志解决方案,我的微调器按预期工作。

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

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

【问题讨论】:

  • 您是否在 mainefest 中处理过屏幕旋转
  • 没有。我不想更改清单。我应该这样做吗?
  • 不更改 mainefest,但添加一个处理程序来告诉应用程序不要在方向更改时重绘元素,否则重绘元素将触发我认为在您的情况下会发生的方法
  • 谷歌这个。关于方向更改处理程序 - android mainefest。

标签: android android-spinner


【解决方案1】:

总的来说,我发现有很多不同的事件可以触发 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);

【讨论】:

  • 很好的答案,谢谢。这应该是公认的答案。
  • 处理android最差小部件的最佳答案。
  • 你是个英雄。我已经在这方面多年了。如果我能给你 100 票,我会
  • 太棒了!!优雅的解决方案之一!
  • 这不处理位置 0 的项目的点击。
【解决方案2】:

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

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

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

一个例子:

我有3 微调器,用户将其中的2 更改为可用选项之一,而不是位置0,所以他最终会遇到这样的情况:

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

现在,当我旋转屏幕时,onItemSelected 将被触发 3 次用于初始微调器设置加上2 次用于不在位置 0 的微调器。

@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 并更新我的计数器以采取相应措施。

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      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 带有评论,这启发了我这个解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-25
        • 1970-01-01
        • 2015-08-13
        • 2012-11-05
        • 2020-05-12
        • 1970-01-01
        相关资源
        最近更新 更多