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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 05:18:47  来源:igfitidea点击:

How to disable onItemSelectedListener to be invoked when setting selected item by code

androidlistenerspinner

提问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 setOnItemSelectedListenerfor 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:

我有一个更简单,我认为更好的解决方案。由于即使在初始化之后我也必须刷新微调器,因此这是一种更通用的方法。请参考接受的答案:

Undesired onItemSelected calls

不需要的 onItemSelected 调用

回答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, onResumeor whatever) are finished.

意思是:即使您在这里和那里设置 Spinner 的值:它们只会更新(视觉上)并且它们的侦听器仅您当前使用的所有方法(如onCreateonResume或其他)完成后才被调用。

This allows the following:

这允许以下内容:

  • keep the selected positions in field variables. (like currentPos1, currentPos2)
  • the listeners onItemSelectedListener()call a method like refreshMyResult()or whatever.
  • when setting positions programmatically, set the spinners andcall your own refresh method manually right after that.
  • 将选定的位置保留在字段变量中。(比如currentPos1currentPos2
  • 侦听器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 falseso 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 OnItemSelectedListenerfor 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);