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

当我创建我的活动时,我设置了一个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) {} } 

这是启动应用程序然后旋转设备时显示的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 

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

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

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

 spinner.post(new Runnable() { public void run() { spinner.setOnItemSelectedListener(listener); } }); 

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

这就是我做的:

做一个局部variables

 Boolean changeSpinner = true; 

在saveInstanceMethod上保存微调器的选定项位置

 @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putInt("ItemSelect",mySpinner.getSelectedItemPosition()); } 

然后在创建的活动中从savedInstanceState获取int,如果int是!= 0,则将booleanvariables设置为false;

 @Override public void onActivityCreated(Bundle savedInstanceState) { if (savedInstanceState!=null) { if (savedInstanceState.getInt("ItemSelect")!=0) { changeSpinner = false; } } } 

最后,从旋转器的OnItemSelected做到这一点

 mySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { public void onItemSelected(AdapterView< ?> parent,android.view.View v, int position, long id) { if (changeSpinner) { [...] } else { changeSpinner= true; } }); 

因此,第一次调用时不会执行任何操作,只需将布尔variables设为true,第二次执行代码即可。 也许不是最好的解决方案,但它有效。

onItemSelected第一次运行时, view尚未膨胀。 第二次它已经膨胀了。 解决方案是使用if (view != null)将方法包装在onItemSelected

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

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

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

关键是第二个参数,表示不animation转换,立即执行动作,然后在onCreate中调用时阻止onItemSelected被触发两次。

尝试这个:

 boolean mConfigChange = false; @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub mConfigChange = false; super.onCreate(savedInstanceState); setContentView(R.layout.activity_mainf); Log.i("SpinnerTest", "Activity onCreate"); ArrayAdapter adapter = ArrayAdapter.createFromResource(this, R.array.colors, android.R.layout.simple_spinner_item); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); ((Spinner) findViewById(R.id.spin)).setAdapter(adapter); ((Spinner) findViewById(R.id.spin)).setSelection(2); ((Spinner) findViewById(R.id.spin)).setOnItemSelectedListener(this); } @Override protected void onResume() { mConfigChange = true; super.onResume(); } @Override public void onItemSelected(AdapterView< ?> spin, View selview, int pos, long selId) { if (!mConfigChange) Log.i("Test", "spin:" + spin + " sel:" + selview + " pos:" + pos + " selId:" + selId); else mConfigChange = false; } 

一旦知道了项目列表和要选择的位置,就可以调用setSelection ,这样就可以避免onItemSelected被调用两次。

我创建了一篇关于我认为更好的方法的文章如何避免onItemSelected在Spinners中被调用两次