Android 屏幕旋转后多次调用微调器 onItemSelected
Android spinner onItemSelected called multiple times after screen rotation
我有一个包含三个微调器的布局。它们的不同之处在于下拉列表中显示的选项。
在我的 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);
正如我所说,我的另外两个微调器几乎相同,但选项不同。
我知道 "first setup" 中的每个微调器都会调用一次 onItemSelected
,所以我有一个标志来防止这个问题。使用此标志解决方案,我的微调器按预期工作。
问题是当我 select 在每个微调器中选择一个选项然后旋转屏幕时。现在,onItemSelected
被调用了 6 次,而不是我预期的 3 次(我设置了一个标志来管理这种调用 3 次的情况)。
为什么会这样,我应该处理这个吗?
我找到了适合我的解决方案。
我有 3
个微调器,因此 onItemSelected
在初始微调器设置时被调用 3
次。为了避免 onItemSelected
在初始设置中触发方法,我创建了一个计数器,因此 onItemSelected
仅根据计数器值触发方法。
我意识到在我的情况下,如果旋转屏幕,onItemSelected
会再次触发 3
次,加上每个不在 [= 位置的微调器的时间19=].
一个例子:
我有 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
并更新我的反对采取相应行动。
总的来说,我发现有许多不同的事件可以触发 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);
要扩展 Andres Q. 的答案...如果您使用的是 Java8,则可以通过使用 lambda 表达式以更少的代码行来完成此操作。此方法还放弃了创建单独的 class 以实现 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
}
});
如果只检查片段是否处于恢复状态呢?像这样思考:
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 带有评论,这启发了我这个解决方案。
我有一个包含三个微调器的布局。它们的不同之处在于下拉列表中显示的选项。
在我的 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);
正如我所说,我的另外两个微调器几乎相同,但选项不同。
我知道 "first setup" 中的每个微调器都会调用一次 onItemSelected
,所以我有一个标志来防止这个问题。使用此标志解决方案,我的微调器按预期工作。
问题是当我 select 在每个微调器中选择一个选项然后旋转屏幕时。现在,onItemSelected
被调用了 6 次,而不是我预期的 3 次(我设置了一个标志来管理这种调用 3 次的情况)。
为什么会这样,我应该处理这个吗?
我找到了适合我的解决方案。
我有 3
个微调器,因此 onItemSelected
在初始微调器设置时被调用 3
次。为了避免 onItemSelected
在初始设置中触发方法,我创建了一个计数器,因此 onItemSelected
仅根据计数器值触发方法。
我意识到在我的情况下,如果旋转屏幕,onItemSelected
会再次触发 3
次,加上每个不在 [= 位置的微调器的时间19=].
一个例子:
我有 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
并更新我的反对采取相应行动。
总的来说,我发现有许多不同的事件可以触发 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);
要扩展 Andres Q. 的答案...如果您使用的是 Java8,则可以通过使用 lambda 表达式以更少的代码行来完成此操作。此方法还放弃了创建单独的 class 以实现 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
}
});
如果只检查片段是否处于恢复状态呢?像这样思考:
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 带有评论,这启发了我这个解决方案。