如果select了非零位置,则在旋转后,微调器的onItemSelectedcallback会被调用两次

当我创build我的活动时,我设置一个微调,分配一个监听器和一个初始值。 我知道onItemSelectedcallback是在应用程序初始化时自动调用的。 我觉得奇怪的是,当设备旋转时会发生两次 ,这导致了一些我不得不绕过的问题。 如果微调器初始select为零,则不会发生这种情况。 我能够找出问题,这是触发它的最简单的活动:

 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 

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

Solutions Collecting From Web of "如果select了非零位置,则在旋转后,微调器的onItemSelectedcallback会被调用两次"

pipe理在另一个stackoverflow问题find解决scheme:

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

一般来说,触发onItemSelected调用的事件似乎有很多,很难跟踪所有的事件。 该解决scheme允许您仅使用OnTouchListener响应用户启动的更改。

创build您的侦听器的侦听器:

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

然后在创build的活动从savedInstanceState获得该int,如果int是!= 0,然后将布尔variables设置为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,第二次就可以执行代码。 也许不是最好的解决scheme,但它的工作。

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转换,立即执行动作,然后阻止onItemSelected在onCreate调用两次被触发。

尝试这个:

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

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

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