不需要的onItemSelected调用

21
我有36个旋转器,我已经初始化了一些值。我使用onItemSelectedListener与它们一起使用。通常,用户可以与这些旋转器进行交互,并触发onItemSelectedListener函数。

一个问题是在初始化时会调用该函数,但我在这里找到解决方案,并使用一个全局变量“count”,并检查是否> 36才执行onItemSelected内的代码,从而避免了这种情况。
我的问题是: 用户有选择点击一个名为“Previous”的按钮,然后我必须重置某些旋转器的值。

我尝试在重置旋转器之前将计数的值更改为0,然后在重置后将其更改回37,但我已经了解到在每个其他函数执行完毕后才会调用onItemSelected,因此即使旋转器的值在被用户选择后立即设置,它仍然在将计数更改回37之后再次调用onItemSelected。
我需要反复刷新某些旋转器,而不触发onItemSelected函数。请问有人可以帮助我找到解决方案吗?谢谢。

请查看以下问题:https://dev59.com/RnE85IYBdhLWcg3w43wX,尝试使用Brad的建议使用 setSelection() - Piotr Chojnacki
3
我已经尝试使用setSelection()和false。但是onItemSelected中的代码仍然被执行。 - Vedavyas Bhat
@Darth Vedar 你可以使用方法 setEnabled(true/false); 根据需要禁用或启用 spinner。 - poojagupta
2
这就是你所说的吗? spin.setEnabled(false); spin.setSelection(pos); spin.setEnabled(true);onItemSelected仍然被调用。 - Vedavyas Bhat
5个回答

78

我发现了一个简单而且我认为优雅的解决方案。 使用标签。 我首先创建了一个名为“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
好的解决方案!运行良好。我之前尝试了很多方法。谢谢! - Rafael
没问题!很高兴它对你有用 :) 请将问题和答案都更新一下。这可能会帮助其他人 :) - Vedavyas Bhat
10
如果您不需要将多个标签附加到Spinner,则可以使用setTag(pos)的简化版本。这样,您就无需为该键创建XML文件。 - Catalin Morosan
5
如果有人需要的话,我已经在这里实现了代码:http://pastebin.com/Jv1Wc70D。 - thd
1
恐怕当 Android 的其他部分在你的代码之外调用 setSelection 时,比如视图首次膨胀或重新膨胀时,这种方法就不起作用了。有人对此有什么想法吗? - NewEndian
显示剩余4条评论

17

当使用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) {
        }
    });

简单点,保持简单! - Guihgo

5

我不知道这个解决方案是否像此处选择的那样万无一失,但它对我很有效,而且似乎更加简单:

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;
    }
}

2
我解决这个问题的方法是先保存OnItemSelectedListener,然后将Spinner的OnItemSelectedListener设置为null值。在通过代码设置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);

5
这是一个不错的想法,但在调用setSelection()之后设置(非空)监听器仍会导致监听器被调用。 - stevehs17

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);
    }
}

一个使用它的例子,在例如Fragment中的onCreateView()中:

    mySpinner = view.findViewById(R.id.history);
    mySpinner.observeSelections()
        .subscribe(this::setSelection);

其中setSelection()是包含视图中的一个方法,如下所示,它被用户选择事件通过Observable调用,以及在编程中的其他地方进行调用,因此处理选择的逻辑适用于两种选择方法。

private void setSelection(int position) {
    if(adapter.isEmpty())
        position = INVALID_POSITION;
    else if(position >= adapter.getCount())
        position = adapter.getCount() - 1;
    MyData result = null;
    mySpinner.pgmSetSelection(position);
    if(position != INVALID_POSITION) {
        result = adapter.getItem(position);
    }
    display(result);  // show the selected item somewhere
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接