不受欢迎的onItemSelected调用

时间:2014-02-13 07:36:23

标签: android android-spinner

我有36个微调器,我用一些值初始化了。我用过onItemSelectedListener。像往常一样,用户可以与这些微调器进行交互,触发onItemSeected函数。

一个问题是调用是在init期间进行的,但我在这里找到了解决方案并避免使用全局变量“count”并检查count> 36在onItemSelected中执行代码之前。

我的问题是: 用户可以选择单击名为“Previous”的按钮,我必须重置一些微调器值。

我尝试在重置微调器之前将count的值更改为0,然后在重置后将其更改回37,但我已经明白只有在每个其他函数执行完毕后才调用onItemSelected,所以它是即使微调器值在用户选择后立即设置,AFTER计数也会更改回37.

我需要重复刷新一些微调器而不触发onItemSelected函数。有谁能帮我找到解决方案?感谢。

5 个答案:

答案 0 :(得分:64)

我找到了一个简单的,我认为优雅的解决方案。 使用标签。 我首先创建了一个名为“tags”的新XML文件,并输入以下代码:

<resources xmlns:android="http://schemas.android.com/apk/res/android">
  <item name="pos" type="id" />
</resources>

每当我自己使用spin.setSelection(pos)时,我也会spin.setTag(R.id.pos, pos),所以我将当前位置设置为标记。

然后,在onItemSelected中,我只执行代码if(spin.getTag(R.id.pos) != position),其中position是函数提供的位置变量。 这样,我的代码仅在用户进行选择时执行。 由于用户已进行选择,因此标签尚未更新,因此在处理完成后,我将标记更新为spin.setTag(R.id.pos, position)

注意:始终使用相同的适配器很重要,或者“position”变量可能指向不同的元素。

编辑:正如kaciula指出的那样,如果您没有使用多个标签,则可以使用更简单的版本,即spin.setTag(pos)spin.getTag(),而无需使用一个XML文件。

答案 1 :(得分:14)

当使用Spinner.setSelection(position)时,它总是激活setOnItemSelectedListener()

为避免触发代码两次,我使用此解决方案:

     private Boolean 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) {
        }
    });

答案 2 :(得分:3)

我不知道这个解决方案是否像这里选择的解决方案一样简单,但它对我来说效果很好,看起来更简单:

boolean executeOnItemSelected = false;
spinner.setSelection(pos)

然后在OnItemSelectedListener

public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
    if(executeOnItemSelected){
        //Perform desired action
    } else {
        executeOnItemSelected = true;
    }
}

答案 3 :(得分:2)

我解决这个问题的方法是先保存OnItemSelectedListener。然后将Spinner的OnItemSelectedListener设置为空值。按代码在Spinner中设置项目后,再次还原OnItemSelectedListener。这对我有用。

见下面的代码:

        // disable the onItemClickListener before changing the selection by code. Set it back again afterwards
        AdapterView.OnItemSelectedListener onItemSelectedListener = historyPeriodSpinner.getOnItemSelectedListener();
        historyPeriodSpinner.setOnItemSelectedListener(null);
        historyPeriodSpinner.setSelection(0);
        historyPeriodSpinner.setOnItemSelectedListener(onItemSelectedListener);

答案 4 :(得分:1)

这是我解决这个问题的方法。我扩展AppCompatSpinner并添加方法pgmSetSelection(int pos),允许编程选择设置而不触发选择回调。我用RxJava对此进行了编码,以便通过Observable传递选择事件。

package com.controlj.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.widget.AdapterView;

import io.reactivex.Observable;

/**
 * Created by clyde on 22/11/17.
 */

public class FilteredSpinner extends android.support.v7.widget.AppCompatSpinner {
    private int lastSelection = INVALID_POSITION;


    public void pgmSetSelection(int i) {
        lastSelection = i;
        setSelection(i);
    }

    /**
     * Observe item selections within this spinner. Events will not be delivered if they were triggered
     * by a call to setSelection(). Selection of nothing will return an event equal to INVALID_POSITION
     *
     * @return an Observable delivering selection events
     */
    public Observable<Integer> observeSelections() {
        return Observable.create(emitter -> {
            setOnItemSelectedListener(new OnItemSelectedListener() {
                @Override
                public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
                    if(i != lastSelection) {
                        lastSelection = i;
                        emitter.onNext(i);
                    }
                }

                @Override
                public void onNothingSelected(AdapterView<?> adapterView) {
                    onItemSelected(adapterView, null, INVALID_POSITION, 0);
                }
            });
        });
    }

    public FilteredSpinner(Context context) {
        super(context);
    }

    public FilteredSpinner(Context context, int mode) {
        super(context, mode);
    }

    public FilteredSpinner(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public FilteredSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    public FilteredSpinner(Context context, AttributeSet attrs, int defStyleAttr, int mode) {
        super(context, attrs, defStyleAttr, mode);
    }
}

其用法示例,例如在onCreateView()的{​​{1}}中调用:

Fragment

其中 mySpinner = view.findViewById(R.id.history); mySpinner.observeSelections() .subscribe(this::setSelection); 是封闭视图中的方法,看起来像这样,并且通过setSelection()从用户选择事件调用,也可以通过编程方式调用,因此处理选择的逻辑很常见两种选择方法。

Observable