Android स्पिनर: प्रारंभ के दौरान onItemSelected कॉल से बचें


156

मैंने a Spinnerऔर a के साथ एक Android एप्लिकेशन बनाया TextView। मैं स्पिनर की ड्रॉप डाउन सूची से चयनित आइटम को TextView में प्रदर्शित करना चाहता हूं। मैंने स्पिनर को onCreateविधि में लागू किया है, इसलिए जब मैं कार्यक्रम चला रहा हूं, तो यह एक मान दिखाता है TextView(ड्रॉप डाउन सूची से आइटम का चयन करने से पहले)।

मैं ड्रॉप डाउन सूची से एक आइटम का चयन करने के बाद ही टेक्स्ट व्यू में मूल्य दिखाना चाहता हूं। मैं यह कैसे करु?

यहाँ मेरा कोड है:

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.TextView;

public class GPACal01Activity extends Activity implements OnItemSelectedListener {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Spinner spinner = (Spinner) findViewById(R.id.noOfSubjects);

        // Create an ArrayAdapter using the string array and a default spinner layout
        ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,R.array.noofsubjects_array, android.R.layout.simple_spinner_item);
        // Specify the layout to use when the list of choices appears
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        // Apply the adapter to the spinner
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(this);
    }

    public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {
        TextView textView = (TextView) findViewById(R.id.textView1);
        String str = (String) parent.getItemAtPosition(pos);
        textView.setText(str);
    }

    public void onNothingSelected(AdapterView<?> arg0) {
        // TODO Auto-generated method stub

    }
}

स्पिनरों का हमेशा एक डिफ़ॉल्ट चयनित मूल्य होता है, यदि आप कोई डिफ़ॉल्ट चयनित मान वाला स्पिनर रखना चाहते हैं, तो आपको अपना कस्टम स्पिनर बनाना चाहिए, या एक खाली प्रविष्टि के साथ एक कस्टम स्पिनर बनाना चाहिए, और getView () विधि में, दृश्यता को बदलना होगा चला गया कच्चे लेआउट
होउसीन

4
इस तरह के कष्टप्रद बग 2018 के अंत में कैसे मौजूद हैं ???
उपयोगकर्ता -123

जवाबों:


174
spinner.setOnItemSelectedListener(this); // Will call onItemSelected() Listener.

इसलिए किसी भी इंटेगर मूल्य के साथ पहली बार इसे संभालें

उदाहरण: शुरू में लो int check = 0;

public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {
   if(++check > 1) {
      TextView textView = (TextView) findViewById(R.id.textView1);
      String str = (String) parent.getItemAtPosition(pos);
      textView.setText(str);
   }
}

आप इसे बूलियन मूल्य के साथ और वर्तमान और पिछले पदों की जांच करके भी कर सकते हैं। यहाँ देखें


2
बहुत बढ़िया आदमी..जब मैंने पहली बार इस समस्या का सामना किया, मैंने कस्टम स्पिनर को लागू करने की कोशिश की..जबकि यह काम नहीं किया..लेकिन आपके समाधान ने एक आकर्षण की तरह काम किया..धन्यवाद।
Sash_KP

1
आप चेक कहां घोषित करते हैं? गेटव्यू के बाहर ()? व्यूहोल्डर के अंदर? कहाँ पे? अपने समाधान की कोशिश की, लेकिन मेरे लिए काम नहीं करता है।
user3718908

9
एक पैच मैं नहीं एक समाधान लगता है।
साक्षाम

1
मैं भी ऐसी ही समस्या का सामना कर रहा हूँ। क्या यह किसी प्रकार की बग है? यह भी कि अगर मैं एक ही आइटम को बार-बार चुनता हूं, तो श्रोता पहली बार काम नहीं करता है। यह तभी काम करता है जब चयन आइटम बदलता है। कोई टिप्पणी, मदद?
अमिताव

1
मैंने अपनी समस्या के साथ इस समाधान की कोशिश की, लेकिन यह केवल एक ही उठता है, उदाहरण के लिए: जब मेरे पास ड्रॉपडाउन पर 2 आइटम हैं, तो यह तब हो जाता है जब मैं किसी भी स्पिनर आइटम को 1 बार चुनता हूं, जब मैं 2 बार कोशिश करता हूं कि यह ठीक से काम नहीं कर रहा है
वसीम

116

इस लाइन को OnItemSelectedListener सेट करने से पहले रखें

spinner.setSelection(0,false)

7
यह एक बेहतर जवाब होगा यदि आप लिखेंगे कि यह कैसे और क्यों मदद करता है।
user3533716

1
यह मदद करता है, लेकिन कैसे करना चाहते हैं?
एईएमलोविजी

14
यह काम करता है क्योंकि आप पहले चयन सेट करते हैं, और फिर एक श्रोता जोड़ते हैं, लेकिन श्रोता को नहीं बुलाया जाएगा क्योंकि आपने पहले ही इस चयन को चुना था। केवल नए चयन श्रोता को बुलाएंगे।
Android डेवलपर

4
यह काम करता है क्योंकि आंतरिक रूप से setSelection(int, boolean)कॉल करता है setSelectionInt(), और आपको इसे कॉल करने के बाद (पहले के बजाय) श्रोता को सेट करने की आवश्यकता है। खबरदार जो setSelection(int)काम नहीं करेगा, क्योंकि यह setNextSelectedPositionInt()आंतरिक रूप से कहता है , और यही मुझे यहां ले गया है।
हाई झांग

3
यदि यह onCreateView () के दौरान या इससे पहले घोषित किया गया है तो यह काम नहीं करता है। onItemSelected कहा जाएगा
अराश

62

एपीआई स्तर 3 के साथ शुरुआत करके आप उपयोगकर्ता के साथ डिवाइस के साथ बातचीत कर रहे हैं, यह निर्धारित करने के लिए बूलियन के साथ एक गतिविधि पर onUserInteraction () का उपयोग कर सकते हैं।

http://developer.android.com/reference/android/app/Activity.html#onUserInteraction ()

@Override
public void onUserInteraction() {
     super.onUserInteraction();
     userIsInteracting = true;
}

मेरे पास गतिविधि पर एक क्षेत्र के रूप में:

 private boolean userIsInteracting;

अंत में, मेरा स्पिनर:

      mSpinnerView.setOnItemSelectedListener(new OnItemSelectedListener() {

           @Override
           public void onItemSelected(AdapterView<?> arg0, View view, int position, long arg3) {
                spinnerAdapter.setmPreviousSelectedIndex(position);
                if (userIsInteracting) {
                     updateGUI();
                }
           }

           @Override
           public void onNothingSelected(AdapterView<?> arg0) {

           }
      });

जैसा कि आप आते हैं और गतिविधि के माध्यम से जाते हैं, बूलियन झूठे पर रीसेट हो जाता है। एक जादू की तरह काम करता है।


3
अच्छा एक बिल..मुझे लगता है कि यह उत्तर के रूप में स्वीकार किए गए से बेहतर समाधान है
रितेश गुने

आप कहाँ मिलेंगे
TheQ

लेखन त्रुटि है? :) setPrepretSelectedIndex ()
Bill Mote

4
यह घोंसले के टुकड़े के मामले में काम नहीं करेगा क्योंकि onUserInteraction गतिविधि विधि है। कोई और उपाय?
चित्रांग

1
@ एरिकबी एनवीएम, यह समझ से बाहर। श्रोता के अंदर इसे गलत तरीके से सेट करना ठीक काम करता है।
सिकंदर

20

इसने मेरे लिए काम किया

एंड्रॉइड में स्पिनर की शुरुआत समस्याग्रस्त है कभी-कभी उपरोक्त समस्या इस पैटर्न द्वारा हल की गई थी।

Spinner.setAdapter();
Spinner.setSelected(false);  // must
Spinner.setSelection(0,true);  //must
Spinner.setonItemSelectedListener(this);

एडेप्टर सेट करना पहला हिस्सा होना चाहिए और एक स्पिनर को इनिशियलाइज़ करते समय OnItemSelectedListener (यह) अंतिम होगा। मेरे OnItemSelected () से ऊपर के पैटर्न को स्पिनर के प्रारंभ के दौरान नहीं कहा जाता है


11

हाहा ... मेरा भी यही सवाल है। जब initViews () बस ऐसा करते हैं। अनुक्रम कुंजी है, श्रोता अंतिम है। शुभ लाभ !

spinner.setAdapter(adapter);
spinner.setSelection(position);
spinner.setOnItemSelectedListener(listener);

अच्छा था! मेरे लिए कुछ भी काम नहीं किया जो भी मैंने पहले लागू किया है, लेकिन इसने मेरे लिए एक आकर्षण की तरह काम किया है। साभार @TreeSouth
दीपिका लालरा

11
मेरे लिए उसी तरह से उपयोग किए जाने वाले स्पिनर.सेट्स सेलेक्शन (स्थिति, गलत) का उपयोग किया। सेटसेलेक्शन (स्थिति) विधि के साथ श्रोता को आरंभीकरण के दौरान बुलाया गया था।
बजे मारियो कुटलेव

2
@HugoGresse स्पिनर को कॉल करने का प्रयास करें। शुरुआत चयन (0, गलत); । बात यह है, अब यह इस स्थिति के चयन को नजरअंदाज कर देगा, क्योंकि यह पहले से ही चयनित है
android डेवलपर

8

मेरा समाधान:

protected boolean inhibit_spinner = true;


@Override
        public void onItemSelected(AdapterView<?> arg0, View arg1,
                int pos, long arg3) {

            if (inhibit_spinner) {
                inhibit_spinner = false;
            }else {

            if (getDataTask != null) getDataTask.cancel(true);
            updateData();
            }

        }

7

प्रारंभिक के दौरान spinner.setOnItemSelectedListener () को कॉल करने से बचने के लिए

spinner.setSelection(Adapter.NO_SELECTION, true); //Add this line before setting listener
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }
});

6

आप इसे इस तरह से कर सकते हैं:

AdapterView.OnItemSelectedListener listener = new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            //set the text of TextView
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    });

yourSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
            yourSpinner.setOnItemSelectedListener(listener);
        }

        @Override
        public void onNothingSelected(AdapterView<?> adapterView) {

        }
    });

सबसे पहले मैं एक श्रोता बनाता हूं और एक चर कॉलबैक के लिए जिम्मेदार ठहराया जाता हूं; तब मैं एक दूसरा श्रोता अनाम बनाता हूं और जब इसे पहली बार कहा जाता है, तो यह श्रोता = बदल देता है]


3

उपयोगकर्ता इंटरैक्शन फ़्लैग को ऑनटच विधि में सच में सेट किया जा सकता है और onItemSelected()एक बार चयन बदलने के बाद इसे रीसेट कर दिया जाता है। मैं इस समाधान को पसंद करता हूं क्योंकि उपयोगकर्ता इंटरैक्शन फ्लैग को विशेष रूप से स्पिनर के लिए नियंत्रित किया जाता है, न कि उस गतिविधि में अन्य विचारों के लिए जो वांछित व्यवहार को प्रभावित कर सकता है।

कोड में:

स्पिनर के लिए अपना श्रोता बनाएं:

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) { 
            userSelect = false;
            // Your selection handling code here
        }
    }

}

के रूप में दोनों एक स्पिनर को श्रोता जोड़े OnItemSelectedListenerऔर एक OnTouchListener:

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

2

इसी तरह का सरल समाधान जो कई स्पिनरों को सक्षम करता है, एडॉप्टर व्यू को एक संग्रह में - एक्टिविटी सुपरक्लास में - onItemSelected (...) के पहले निष्पादन पर रखा जाता है, फिर यह देखने के लिए देखें कि क्या एडेप्टर व्यू निष्पादित करने से पहले संग्रह में है या नहीं। यह सुपरक्लास में तरीकों के एक सेट को सक्षम करता है और कई एडेप्टर व्यूज़ का समर्थन करता है और कई स्पिनरों को लागू करता है।

सुपरक्लास ...

private Collection<AdapterView> AdapterViewCollection = new ArrayList<AdapterView>();

   protected boolean firstTimeThrough(AdapterView parent) {
    boolean firstTimeThrough = ! AdapterViewCollection.contains(parent);
    if (firstTimeThrough) {
       AdapterViewCollection.add(parent);
     }
    return firstTimeThrough;
   }

उपवर्ग ...

public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
      if (! firstTimeThrough(parent)) {
        String value = safeString(parent.getItemAtPosition(pos).toString());
        String extraMessage = EXTRA_MESSAGE;
        Intent sharedPreferencesDisplayIntent = new         Intent(SharedPreferencesSelectionActivity.this,SharedPreferencesDisplayActivity.class);
    sharedPreferencesDisplayIntent.putExtra(extraMessage,value);
    startActivity(sharedPreferencesDisplayIntent);
  }
  // don't execute the above code if its the first time through
  // do to onItemSelected being called during view initialization.

}


2

बूलियन फ़ील्ड बनाएं

private boolean inispinner;

गतिविधि के भीतर

    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            if (!inispinner) {
                inispinner = true;
                return;
            }
            //do your work here
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {

        }
    });


1

आप इसे पहले setOnTouchListener द्वारा प्राप्त कर सकते हैं, फिर onTouch में SetOnItemSelectedListener सेट करें

@Override
public boolean onTouch(final View view, final MotionEvent event) {
 view.setOnItemSelectedListener(this)
 return false;
}

मुझे यह पसंद है। हालांकि यह हर बार एक नया श्रोता बनाता है जब कोई उपयोगकर्ता दृश्य को छूता है। इसलिए मैं पहले निर्मित श्रोता को कैश करना और उसका पुन: उपयोग करना पसंद करता हूं।
Vlad

1

यह मेरे लिए काम किया:

    spinner.setSelection(0, false);
    new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                spinner.setOnItemSelectedListener(listener);
            }, 500);

1

अभि के जवाब के आधार पर मैंने इसे सरल श्रोता बनाया

class SpinnerListener constructor(private val onItemSelected: (position: Int) -> Unit) : AdapterView.OnItemSelectedListener {

    private var selectionCount = 0

    override fun onNothingSelected(parent: AdapterView<*>?) {
        //no op
    }

    override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
        if (selectionCount++ > 1) {
           onItemSelected(position)
        }
    }
}

0

एक ही समस्या थी और यह मेरे लिए काम करता है:

मेरे पास 2 स्पिनर हैं और मैं उन्हें init के दौरान और अन्य नियंत्रणों के साथ बातचीत के दौरान या सर्वर से डेटा प्राप्त करने के बाद अपडेट करता हूं।

यहाँ मेरा टेम्पलेट है:

public class MyClass extends <Activity/Fragment/Whatever> implements Spinner.OnItemSelectedListener {

    private void removeSpinnersListeners() {
        spn1.setOnItemSelectedListener(null);
        spn2.setOnItemSelectedListener(null);
    }

    private void setSpinnersListeners() {
        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                spn1.setOnItemSelectedListener(MyClass.this);
                spn2.setOnItemSelectedListener(MyClass.this);
            }
        }, 1);
    }

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
        // Your code here
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {

    }
}

जब वर्ग श्रोता को सीधे सेट करने के बजाय उपयोग सेटस्पिनर्सलिस्टर्स () आरंभ कर रहा है।

Runnable आप अपने मूल्यों को सेट करने के बाद स्पिनर को onItemSelected फायरिंग से रोक देगा।

आप स्पिनर (एक सर्वर कॉल के बाद आदि) उपयोग अद्यतन करना चाहते हैं removeSpinnersListeners () सही अपने अद्यतन लाइनों से पहले, और ) setSpinnersListeners ( सही अद्यतन लाइनों के बाद। यह अपडेट के बाद onItemSelected को फायरिंग से रोकेगा।


0

कोड

spinner.setOnTouchListener(new View.OnTouchListener() { 
@Override public boolean onTouch(View view, MotionEvent motionEvent) { isSpinnerTouch=true; return false; }});

holder.spinner_from.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> adapterView, View view, int slot_position, long l) {
                if(isSpinnerTouch)
                {
                    Log.d("spinner_from", "spinner_from");
                    spinnerItemClickListener.onSpinnerItemClickListener(position, slot_position, AppConstant.FROM_SLOT_ONCLICK_CODE);
                }
                else {

                }
            }

            @Override
            public void onNothingSelected(AdapterView<?> adapterView) {

            }
        });

0

मेरे लिए, अभि का समाधान एपी स्तर 27 तक बहुत अच्छा काम करता है।

लेकिन ऐसा लगता है कि Api स्तर 28 और ऊपर से, onItemSelected () नहीं कहा जाता है जब श्रोता सेट किया जाता है, जिसका अर्थ है onItemSelected () कभी नहीं कहा जाता है।

इसलिए, मैंने एपीआई स्तर की जाँच करने के लिए एक छोटा सा विवरण दिया है:

public void onItemSelected(AdapterView<?> parent, View arg1, int pos,long id) {

            if(Build.VERSION.SDK_INT >= 28){ //onItemSelected() doesn't seem to be called when listener is set on Api 28+
                check = 1;
            }

            if(++check > 1) {
                //Do your action here
            }
        }

मुझे लगता है कि यह काफी अजीब है और मुझे यकीन नहीं है कि दूसरों को भी यह समस्या है, लेकिन मेरे मामले में इसने अच्छा काम किया।


0

मैंने स्पिनर के ऊपर एक TextView, उसी आकार और पृष्ठभूमि को स्पिनर के रूप में रखा, ताकि उपयोगकर्ता के उस पर क्लिक करने से पहले जो दिखे, उस पर मेरा अधिक नियंत्रण हो। टेक्स्टव्यू के साथ, मैं टेक्स्टव्यू का इस्तेमाल उस झंडे के लिए भी कर सकता हूं जब उपयोगकर्ता ने बातचीत शुरू की हो।

मेरा कोटलिन कोड कुछ इस तरह दिखता है:

private var mySpinnerHasBeenTapped = false

private fun initializeMySpinner() {

    my_hint_text_view.setOnClickListener {
        mySpinnerHasBeenTapped = true //turn flag to true
        my_spinner.performClick() //call spinner click
    }

    //Basic spinner setup stuff
    val myList = listOf("Leonardo", "Michelangelo", "Rafael", "Donatello")
    val dataAdapter: ArrayAdapter<String> = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item, myList)
    my_spinner.adapter = dataAdapter

    my_spinner.onItemSelectedListener = object : OnItemSelectedListener {

        override fun onItemSelected(parent: AdapterView<*>?, view: View, position: Int, id: Long) {

            if (mySpinnerHasBeenTapped) { //code below will only run after the user has clicked
                my_hint_text_view.visibility = View.GONE //once an item has been selected, hide the textView
                //Perform action here
            }
        }

        override fun onNothingSelected(parent: AdapterView<*>?) {
            //Do nothing
        }
    }
}

लेआउट फ़ाइल कुछ इस तरह दिखती है, जिसमें महत्वपूर्ण हिस्सा यह है कि स्पिनर और टेक्स्ट व्यू समान चौड़ाई, ऊंचाई और मार्जिन साझा करते हैं:

        <FrameLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <Spinner
                android:id="@+id/my_spinner"
                android:layout_width="match_parent"
                android:layout_height="35dp"
                android:layout_marginStart="10dp"
                android:layout_marginEnd="10dp"
                android:background="@drawable/bg_for_spinners"

                android:paddingStart="8dp"
                android:paddingEnd="30dp"
                android:singleLine="true" />

            <TextView
                android:id="@+id/my_hint_text_view"
                android:layout_width="match_parent"
                android:layout_height="35dp"                
                android:layout_marginStart="10dp"
                android:layout_marginEnd="10dp"
                android:background="@drawable/bg_for_spinners"

                android:paddingStart="8dp"
                android:paddingEnd="30dp"
                android:singleLine="true"
                android:gravity="center_vertical"
                android:text="*Select A Turtle"
                android:textColor="@color/green_ooze"
                android:textSize="16sp" />

        </FrameLayout>

मुझे यकीन है कि अन्य समाधान कार्य जहां आप पहले onItemSelected कॉल को अनदेखा करते हैं, लेकिन मुझे वास्तव में यह मानने का विचार पसंद नहीं है कि इसे हमेशा कहा जाएगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.