如果选择了非零位置,则旋转后Spinner的onItemSelected回调调用两次

ath*_*hos 28 android android-widget android-spinner

当我创建我的活动时,我设置了一个Spinner,为它分配一个监听器和一个初始值.我知道onItemSelected在应用程序初始化期间会自动调用回调.我觉得很奇怪的是,当设备旋转时会发生两次这种情况,这会导致我遇到一些问题,我不得不绕过它.如果微调器初始选择为零,则不会发生这种情况.我能够隔离问题,这是触发它的最简单的活动:

public class MainActivity extends Activity implements OnItemSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Log.i("Test","Activity onCreate");
    setContentView(R.layout.activity_main);
    ((Spinner)findViewById(R.id.spinner1)).setSelection(2);
    ((Spinner)findViewById(R.id.spinner1)).setOnItemSelectedListener(this);
}
@Override
public void onItemSelected(AdapterView<?> spin, View selview, int pos, long selId)
{
    Log.i("Test","spin:"+spin+" sel:"+selview+" pos:"+pos+" selId:"+selId);
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {}
}
Run Code Online (Sandbox Code Playgroud)

这是启动应用程序然后旋转设备时显示的logcat:

    I/Test( 9881): spin:android.widget.Spinner@4052f508 sel:android.widget.TextView@40530b08 pos:2 selId:2
    I/Test( 9881): Activity onCreate
    I/Test( 9881): spin:android.widget.Spinner@40535d80 sel:android.widget.TextView@40538758 pos:2 selId:2
    I/Test( 9881): spin:android.widget.Spinner@40535d80 sel:android.widget.TextView@40538758 pos:2 selId:2
Run Code Online (Sandbox Code Playgroud)

这是预期的行为吗?我错过了什么吗?

Rap*_*ira 46

管理在另一个stackoverflow问题中找到解决方案:

spinner.post(new Runnable() {
    public void run() {
        spinner.setOnItemSelectedListener(listener);
    }
});
Run Code Online (Sandbox Code Playgroud)

  • 你能把这个SOF问题链接起来吗? (2认同)
  • 3 年后,非常感谢您 &lt;3 解决了我从片段 B 返回到片段 A 时 Spinner 发射两次的问题,其中 Spinner 位于片段 A 上。 (2认同)
  • 不要这样做!是一个丑陋的解决方法.最简单的方法是在设置监听器之前使用setSelection(#,false).请参阅/sf/answers/3148542071/ (2认同)
  • 这在设置侦听器时解决了初始双重调用.不幸的是,每次更改选择时都无法解决双重调用问题 (2认同)

小智 20

通常,似乎有许多事件触发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;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

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

SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);
Run Code Online (Sandbox Code Playgroud)

  • 此解决方案似乎无法访问...使用TalkBack或其他一些屏幕阅读器应用程序使用其设备的用户可能不会以这种方式触发选择. (3认同)

One*_*Man 8

只需在设置侦听器之前使用 setSelection(#, false) :

@Override
protected void onCreate(Bundle savedInstanceState) {
    ...
    spinner.setSelection(2, false);
    spinner.setOnItemSelectedListener(this);
}
Run Code Online (Sandbox Code Playgroud)

关键是第二个参数。它说不要为过渡设置动画,立即执行操作并防止 onItemSelected 被触发两次,因为系统已经进行了调用。


Tan*_*han 6

第一次onItemSelected运行时,view尚未充气。第二次它已经膨胀了。解决方案是将方法onItemSelectedif (view != null).

@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
    if (view != null) { 
        //do things here

    }
}
Run Code Online (Sandbox Code Playgroud)