不希望的onItemSelected调用

问题描述:

我有36个spinners,我已经初始化了一些值。我已经使用onItemSelectedListener。像往常一样,用户可以与这些spinners进行交互,触发onItemSeected函数。不希望的onItemSelected调用

一个问题是初始化过程中调用时,但我在这里找到解决方案,并避免使用全局变量“计数”,并检查是否计数> 36的内部onItemSelected执行代码之前。

我的问题是这样的: 用户可以选择点击一个叫做“Previous”的按钮,在这个按钮上我必须重置一些微调值。

我试着在重置spinners之前将count的值改为0,然后在重置后将它重新更改为37,但是我明白了onItemSelected仅在每个其他函数执行完毕后才会调用,所以它称为AFTER计数会重新变回37,即使微调器值在用户选择时立即设置。

我需要反复刷新一些spinners而不会触发onItemSelected函数。任何人都可以帮我找到解决方案吗?谢谢。

+0

检查此问题:http://*.com/questions/2562248/android-how-to-keep-onitemselected-from-firing-off-on-a-newly-instantiated-spin并尝试遵循布拉德的建议使用'setSelection()'。 –

+3

我已经尝试使用setSelection()和false。 onItemSelected内部的代码仍然执行。 –

+0

@Darth Vedar您可以使用方法setEnabled(true/false)按照您的要求禁用和启用微调器; – poojagupta

我发现一个简单的,我认为,优雅的解决方案。 使用标签。 我先创建一个名为“标签”,把下面的代码一个新的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),其中位置是通过函数提供的位置可变。 这样,我的代码只有在用户正在进行选择时才会执行。 由于用户已经做出选择,标签还没有更新,所以处理完成后,我将标签更新为spin.setTag(R.id.pos, position)

注意:要使用整个同一个适配器是很重要的,还是“位置”变量可能指向不同的元素。

编辑:作为kaciula指出的那样,如果你不使用多个标签,则可以使用简单的版本,那就是spin.setTag(pos)spin.getTag()而不需要一个XML文件。

+1

好的解决方案!工作正常。我之前尝试了很多东西。谢谢! – Rafael

+0

没问题!很高兴它为你工作:)请一个问题和答案。它可能会帮助其他人:) –

+8

如果您不需要将几个标签附加到微调器,您还可以使用setTag(pos)的简化版本。这样你就不需要为密钥创建xml文件。 –

当Spinner.setSelection(位置)时,它总是激活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) { 
     } 
    }); 
+0

tks - 保持简单! – Guihgo

我解决的办法,这是通过保存首先OnItemSelectedListener。然后将Spinner的OnItemSelectedListener设置为空值。通过代码在微调器中设置项目后,再次恢复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); 
+1

这是一个好主意,但在调用setSelection()之后设置(非空)侦听器仍然会导致侦听器被调用。 – stevehs17

这里是我解决这个问题。我扩展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 
} 

我不知道,如果这个解决方案是在这里所选择的一个为做到万无一失,但它很适合我,似乎更简单:

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