Android 如何在通过代码设置所选项目时禁用要调用的 onItemSelectedListener
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2297601/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to disable onItemSelectedListener to be invoked when setting selected item by code
提问by Zordid
Just wondering how you handle the following problem: a result is calculated depending on two spinners' selected items. To handle the UI things, i.e. a user picks a new item in one of the spinners, I install a listener using setOnItemSelectedListener
for the spinner in my onCreate()
method of the activity.
只是想知道您如何处理以下问题:根据两个微调器的选定项目计算结果。为了处理 UI 的事情,即用户在一个微调器中选择一个新项目,我setOnItemSelectedListener
在我onCreate()
的活动方法中安装了一个用于微调器的监听器。
Now: that works, of course, fine. The listener's work is to trigger a new calculation of the result.
现在:当然可以。监听器的工作是触发新的计算结果。
The problem: because I intercept onPause()
onResume()
to save/restore the last state, I got a method that setsthese two spinners' selected item programmatically like in here:
问题:因为我拦截onPause()
onResume()
以保存/恢复最后一个状态,所以我得到了一个方法来以编程方式设置这两个微调器的选定项目,如下所示:
startSpinner.setSelection(pStart);
destSpinner.setSelection(pDest);
These two calls invoke the listeners, too! My calculation method for the result plus the notification of a new result set is invoked twice here!
这两个调用也调用了侦听器!我对结果的计算方法加上新结果集的通知在这里调用了两次!
A stupid direct approach for this would be to have a boolean variable disablingwhatever the listener does inside, setting it before setting the selected items and resetting it afterwards. Okay. But is there a better method??
一个愚蠢的直接方法是让一个布尔变量禁用监听器在内部所做的任何事情,在设置所选项目之前设置它并在之后重置它。好的。但是有更好的方法吗??
I don't want listeners to be called by code - actions, only by user actions! :-(
我不希望侦听器被代码调用 - 动作,只能通过用户动作!:-(
How do you do it? Thanks!
你怎么做呢?谢谢!
采纳答案by Vedavyas Bhat
I have an easier, and I think, better solution. Since I had to refresh the spinners even after initialization, this is a more generic approach. Please refer the accepted answer:
我有一个更简单,我认为更好的解决方案。由于即使在初始化之后我也必须刷新微调器,因此这是一种更通用的方法。请参考接受的答案:
回答by Andres Q.
A cleaner solution, in my opinion, to differentiate between programmatic and user-initiated changes is the following:
在我看来,区分程序化更改和用户启动更改的更清晰的解决方案如下:
Create your listener for the spinner as both an OnTouchListener and OnItemSelectedListener
为微调器创建监听器作为 OnTouchListener 和 OnItemSelectedListener
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;
}
}
}
Add the listener to the spinner registering for both event types
将侦听器添加到为两种事件类型注册的微调器
SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);
This way, any unexpected calls to your handler method due to initialization or re-initialization will be ignored.
这样,由于初始化或重新初始化而对处理程序方法的任何意外调用都将被忽略。
回答by Zordid
Okay, I got it working the way I want to now.
好的,我让它按照我现在想要的方式工作。
The thing to understand here (and I did not when I was writing that question...) is that everything in Android runs in one thread - the UI thread.
这里要理解的事情(我在写这个问题时没有理解......)是 Android 中的一切都在一个线程中运行 - UI 线程。
Meaning: even though you set Spinner's values here and there: they are only updated (visually) andtheir listeners are only called afterall methods you're currently in (like onCreate
, onResume
or whatever) are finished.
意思是:即使您在这里和那里设置 Spinner 的值:它们只会更新(视觉上)并且它们的侦听器仅在您当前使用的所有方法(如onCreate
,onResume
或其他)完成后才被调用。
This allows the following:
这允许以下内容:
- keep the selected positions in field variables. (like
currentPos1
,currentPos2
) - the listeners
onItemSelectedListener()
call a method likerefreshMyResult()
or whatever. - when setting positions programmatically, set the spinners andcall your own refresh method manually right after that.
- 将选定的位置保留在字段变量中。(比如
currentPos1
,currentPos2
) - 侦听器
onItemSelectedListener()
调用类似的方法refreshMyResult()
或其他方法。 - 以编程方式设置位置时,设置微调器并在此之后立即手动调用您自己的刷新方法。
The refreshMyResult()
method looks like this:
该refreshMyResult()
方法如下所示:
int newPos1 = mySpinner1.getSelectedItemPosition();
int newPos2 = mySpinner2.getSelectedItemPosition();
// only do something if update is not done yet
if (newPos1 != currentPos1 || newPos2 != currentPos2) {
currentPos1 = newPos1;
currentPos2 = newPos2;
// do whatever has to be done to update things!
}
Because the listeners will be called later - and by then, the remembered position in currentPos is already updated - nothing will happen and no unnecessary update of anything else will take place. When a user selects a new value in one of the spinners, well - the update will be performed accordingly!
因为稍后将调用侦听器 - 届时, currentPos 中记住的位置已经更新 - 不会发生任何事情,也不会发生任何其他不必要的更新。当用户在其中一个微调器中选择一个新值时,好吧 - 将相应地执行更新!
That's it! :-)
就是这样!:-)
Ahh - one more thing: the answer to my question is: No. The listeners cannot be disabled (easily) and will be called whenever a value is changed.
啊——还有一件事:我的问题的答案是:不。侦听器不能(很容易)被禁用,只要值改变就会被调用。
回答by Venkatesh
First add boolean values for stopping spinner listener call
首先添加布尔值以停止微调器侦听器调用
Boolean check = false;
Then you add on Touch listener and on Item click Listener Like below code
然后你添加触摸监听器和项目点击监听器如下代码
holder.filters.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
check = true;
return false;
}
});
holder.filters.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener()
{
@Override
public void onItemSelected(AdapterView<?> parent, View arg1, int position, long id)
{
flag = filterids.get(position);
if(check)
{
check = false;
new Applyfilters().execute(flag,"3");
}else{
}
}
@Override
public void onNothingSelected(AdapterView<?> arg0)
{
// TODO Auto-generated method stub
}
});
Its simple working good for stopping server call multiple times.
它的简单工作有益于多次停止服务器调用。
回答by a.black13
I created a library that help for all, that no need to call item onClick action in Spinner For example:
我创建了一个对所有人都有帮助的库,不需要在 Spinner 中调用 item onClick 操作例如:
spinner.setSelection(withAction,position);
where withAction is a boolean flag, that used for call or not item action
其中 withAction 是一个布尔标志,用于调用或不调用项目操作
Link on Github: https://github.com/scijoker/spinner2
Github 上的链接:https: //github.com/scijoker/spinner2
回答by joe
It is very easy you can call the Spinner.setSelection(int position, boolean animate)
method with false
so the listeners will not react on the change.
您可以很容易地调用该Spinner.setSelection(int position, boolean animate)
方法,false
因此侦听器不会对更改做出反应。
回答by P01550n
Spinner.setSelection(int position, boolean animate) does trigger the listener on 4.3
Spinner.setSelection(int position, boolean animate) 在 4.3 上触发监听器
回答by Graeme Duncan
Add the OnItemSelectedListener
for each spinner afteryou have set any previous value in onResume
.
在中设置任何先前的值后,OnItemSelectedListener
为每个微调器添加。onResume
回答by Ivo Stoyanov
When Spinner.setSelection(position) is used, it always activates setOnItemSelectedListener()
当使用 Spinner.setSelection(position) 时,它总是激活 setOnItemSelectedListener()
To avoid firing the code twice I use this solution:
为了避免两次触发代码,我使用了这个解决方案:
private mIsSpinnerFirstCall=true;
...
Spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
//If a new value is selected (avoid activating on setSelection())
if(!mIsSpinnerFirstCall) {
// Your code goes gere
}
mIsSpinnerFirstCall = false;
}
public void onNothingSelected(AdapterView<?> arg0) {
}
});
This solution is valid when you are sure that Spinner.setSelection(position) us used. Also, it is important to set mIsSpinnerFirstCall=true each time before using Spinner.setSelection(position)
当您确定我们使用了 Spinner.setSelection(position) 时,此解决方案是有效的。此外,在使用 Spinner.setSelection(position) 之前每次都设置 mIsSpinnerFirstCall=true 很重要
回答by Burak
My solution is very easy. First initialize a global boolean variable.
我的解决方案很简单。首先初始化一个全局布尔变量。
boolean shouldWork = true;
Then use below code in your onCreate() method.
然后在您的 onCreate() 方法中使用以下代码。
Spinner spinner = findViewById(R.id.spinner);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView adapter, View v, int i, long lng) {
if (shouldWork) {
// Do your actions here
}
else
shouldWork = true;
}
public void onNothingSelected(AdapterView<?> parentView) {
}
});
Now you can use the setSelection method in everwhere without invoking the onItemSelected() method by below code.
现在您可以在任何地方使用 setSelection 方法,而无需通过以下代码调用 onItemSelected() 方法。
shouldWork = false;
spinner.setSelection(0);