選択したアイテムをコードで設定するときに、onitemselectedListenerを無効にする方法

StackOverflow https://stackoverflow.com/questions/2297601

  •  21-09-2019
  •  | 
  •  

質問

次の問題をどのように処理するか疑問に思うだけです。結果は、2つのスピナーの選択されたアイテムに応じて計算されます。 UIのものを処理するために、つまりユーザーがスピナーの1つで新しいアイテムを選択します。 setOnItemSelectedListener 私のスピナーのために onCreate() アクティビティの方法。

さて:もちろん、それはうまくいきます。リスナーの作業は、結果の新しい計算をトリガーすることです。

問題:私は傍受しているからです onPause() onResume() 最後の状態を保存/復元するために、私はその方法を得ました セット これら2つのスピナーの選択されたアイテムは、ここにプログラム的に似ています:

startSpinner.setSelection(pStart);
destSpinner.setSelection(pDest);

これらの2つの電話もリスナーを呼び出します!結果の私の計算方法に加えて、新しい結果セットの通知がここで2回呼び出されます!

これに対する愚かな直接的なアプローチは、ブール変数を持つことです 無効化 リスナーが内部で何をするにしても、選択したアイテムを設定する前に設定し、その後リセットします。わかった。しかし、より良い方法はありますか?

リスナーがコードによって呼ばれることを望んでいません - アクション、ユーザーアクションによってのみ! :-(

どうしますか?ありがとう!

役に立ちましたか?

解決

私は簡単に、より良い解決策を持っていると思います。初期化後でもスピナーをリフレッシュする必要があったため、これはより一般的なアプローチです。受け入れられた答えを参照してください:

望ましくないONITEMSELECTEDコール

他のヒント

私の意見では、プログラマティックとユーザーが開始した変更を区別するためのよりクリーンなソリューションは、次のとおりです。

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

}

両方のイベントタイプに登録するスピナーにリスナーを追加します

SpinnerInteractionListener listener = new SpinnerInteractionListener();
mSpinnerView.setOnTouchListener(listener);
mSpinnerView.setOnItemSelectedListener(listener);

このようにして、初期化または再開始により、ハンドラー方法への予期しない呼び出しは無視されます。

さて、私は今やりたい方法でそれを機能させました。

ここで理解すべきこと(そして、私はその質問を書いていたときにそうしませんでした...)は、Androidのすべてが1つのスレッドであるUIスレッドで実行されるということです。

意味:スピナーの値をあちこちに設定しても:それらは(視覚的に)更新されるだけです 彼らのリスナーはと呼ばれています 現在のすべてのメソッド(次のように onCreate, onResume または何でも)終了しました。

これにより、次のことが可能です。

  • 選択した位置をフィールド変数に保持します。 (お気に入り currentPos1, currentPos2)
  • リスナー onItemSelectedListener() 次のような方法を呼び出します refreshMyResult() または何でも。
  • プログラムで位置を設定するときは、スピナーを設定します その後、独自の更新方法を手動で呼び出してください。

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!

}

リスナーは後で呼び出されるため、そしてそれまでにCurrentPosで記憶されている位置はすでに更新されています - 何も起こらず、他の何かの不必要な更新は行われません。ユーザーがスピナーの1つで新しい値を選択すると、それに応じて更新が実行されます!

それでおしまい! :-)

ああ - もう1つ:私の質問に対する答えは次のとおりです。いいえ。リスナーは(簡単に)無効にすることができず、値が変更されるたびに呼び出されます。

最初に、スピナーリスナーコールを停止するためにブール値を追加します

  Boolean check = false;

次に、タッチリスナーを追加し、アイテムに以下のコードをクリックします

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

サーバーコールを複数回停止するのに適しています。

あなたが呼ぶことができるのはとても簡単です Spinner.setSelection(int position, boolean animate) での方法 false したがって、リスナーは変化に反応しません。

spinner.setselection(int position、boolean animate)は、4.3でリスナーをトリガーします

私はすべての人に役立つライブラリを作成しました。たとえば、スピナーでアクションをオンクリックするアイテムを呼び出す必要はありません。

spinner.setSelection(withAction,position);

装具はブールフラグであり、呼び出しに使用されるかどうかのアイテムアクションに使用されます

Githubのリンク:https://github.com/scijoker/spinner2

追加します OnItemSelectedListener スピナーごとに 以前の値をに設定しました onResume.

Spinner.setSelection(position)が使用されると、常にsetOnitemselectedListener()をアクティブにします

コードを2回起動しないようにするために、このソリューションを使用します。

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

このソリューションは、Spinner.Setselection(Position)が使用していることを確認した場合に有効です。また、spinner.setelection(position)を使用する前に、misspinnerfirstcall =毎回trueを設定することが重要です

私の解決策はとても簡単です。最初にグローバルブール変数を初期化します。

boolean shouldWork = true;

次に、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)  {

    }
});

これで、以下のコードでonitemSelected()メソッドを呼び出すことなく、EverwhereでSetSelectionメソッドを使用できます。

shouldWork = false;
spinner.setSelection(0);
    This following method will help you to stop invoking automatically the selection listener


    yourspinnerobj.post(new Runnable() {
                @Override
                public void run() {
                    yourspinnerobj.setOnItemSelectedListener(yourspinnerlistener);
                }
            });
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top