当我创建活动时,我设置了一个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
这是预期的行为吗?我错过了什么吗?
答案 0 :(得分:46)
管理以在另一个stackoverflow问题中找到解决方案:
spinner.post(new Runnable() {
public void run() {
spinner.setOnItemSelectedListener(listener);
}
});
答案 1 :(得分:18)
通常,似乎有许多事件触发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);
答案 2 :(得分:3)
onItemSelected
第一次运行时,view
尚未充气。第二次它已经膨胀了。解决方案是使用onItemSelected
将方法包装在if (view != null)
内。
@Override
public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
if (view != null) {
//do things here
}
}
答案 3 :(得分:3)
在设置监听器之前,只需使用setSelection(#,false):
@Override
protected void onCreate(Bundle savedInstanceState) {
...
spinner.setSelection(2, false);
spinner.setOnItemSelectedListener(this);
}
键是第二个参数,表示不动画转换,立即执行动作,然后在onCreate中调用时阻止onItemSelected被触发两次。
答案 4 :(得分:2)
这就是我所做的:
做一个局部变量
Boolean changeSpinner = true;
在saveInstanceMethod上保存微调器的选定项目位置
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("ItemSelect",mySpinner.getSelectedItemPosition());
}
然后在创建的活动中从savedInstanceState获取int,如果int是!= 0,则将布尔变量设置为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;
}
});
因此,第一次调用时不会执行任何操作,只需将布尔变量设为true,第二次执行代码即可。 也许不是最好的解决方案,但它有效。
答案 5 :(得分:0)
试试这个:
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;
}
答案 6 :(得分:0)
一旦您知道项目列表和要选择的位置,就可以致电var m, n;
m = 1;
while(m <= 5) {
n = 1;
while(n <= 10) {
document.write("*" + " ");
n++;
}
document.write("<br>");
m++;
}
,这样就可以避免两次调用setSelection
。
我创建了一篇关于我认为更好的方法的文章How to avoid onItemSelected to be called twice in Spinners
答案 7 :(得分:0)
我正在Kotlin中更新@Andres Q.的答案。
创建一个内部类,在其中使用Spinner
inner class SpinnerInteractionListener : AdapterView.OnItemSelectedListener, View.OnTouchListener {
override fun onNothingSelected(parent: AdapterView<*>?) {
}
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
if (userSelect) {
//Your selection handling code here
userSelect = false
}
}
@SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
userSelect = true
return false
}
internal var userSelect = false
}
然后在onCreate()
外部将实例变量声明为全局变量,如
lateinit var spinnerInteractionListener: SpinnerInteractionListener
然后通过{p>在onCreate()
内部对其进行初始化
spinnerInteractionListener = SpinnerInteractionListener()
并像使用它
spinnerCategory.onItemSelectedListener = spinnerInteractionListener
spinnerCategory.setOnTouchListener(spinnerInteractionListener)
这里spinnerCategory
是Spinner
答案 8 :(得分:0)
我编写了一个扩展函数,可以跳过除用户发起的所有选择事件之外的所有选择事件。 如果您不使用第一个默认微调器位置,请不要忘记覆盖 defPosition
fun Spinner.setFakeSelectSkipWatcher(execute: (position: Int) -> Unit, defPosition: Int = 0) {
val listener = object : AdapterView.OnItemSelectedListener {
var previousIsNull = -1
var notSkip = false
override fun onItemSelected(p0: AdapterView<*>?, view: View?, position: Int, p3: Long) {
if (notSkip) execute(position)
else {
if ((view != null && position == defPosition) ||
(view == null && position == defPosition) ||
(view != null && previousIsNull == 1 && position != defPosition)
) notSkip = true
}
previousIsNull = if (view == null) 1 else 0
}
override fun onNothingSelected(p0: AdapterView<*>?) {}
}
onItemSelectedListener = listener
}