Android spinner close - android

I have an activity with a spinner, and I was wondering if it is possible to close the spinner programmatically, if the user has opened it.
The whole story is that in the background I am running a process on a separate thread. When the process has finished, I invoke a Handler on the main activity and, depending on the outcome, I perform some tasks. It is then that I want to close the spinner, it the user has opened it.
The spinner is in the main.xml layout:
<Spinner android:id="#+id/birthPlaceSpinner" android:layout_weight="1"
android:layout_height="wrap_content" android:prompt="#string/select"
android:layout_width="fill_parent" />
and this is the Handler:
private class BirthplaceChangedHandler extends Handler {
#Override
public void handleMessage(Message msg) {
String placeFilterStr = birthPlaceFilterText.getText().toString();
if ("".equals(placeFilterStr) || placeFilterStr == null || validNewAddresses.isEmpty()) {
birthPlaceSpinner.setEnabled(false);
hideGeoLocationInformation();
} else {
birthPlaceSpinner.setEnabled(true);
}
adapter = new ArrayAdapter<String>(getApplicationContext(), R.layout.multiline_spinner_dropdown_item, validNewAddressesStr)
birthPlaceSpinner.setAdapter(adapter);
}
}
Cheers!

public static void hideSpinnerDropDown(Spinner spinner) {
try {
Method method = Spinner.class.getDeclaredMethod("onDetachedFromWindow");
method.setAccessible(true);
method.invoke(spinner);
} catch (Exception e) {
e.printStackTrace();
}
}

This works for me:
class SomeAdapter extends BaseAdapter implements SpinnerAdapter {
//......
public View getDropDownView(int position, View convertView, ViewGroup parent) {
View view = convertView;
if (view == null) {
//......
}
view.setOnClickListener(new ItemOnClickListener(parent));
return view;
}
//.....
}
and the click listener:
class ItemOnClickListener implements View.OnClickListener {
private View _parent;
public ItemOnClickListener(ViewGroup parent) {
_parent = parent;
}
#Override
public void onClick(View view) {
//.......
// close the dropdown
View root = _parent.getRootView();
root.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
root.dispatchKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK));
}
}

Well its a little complicated than I thought.
I am adding the step by step details here. Try to follow it. I was able to achieve this in api level 10.
And this solution assumes that you are supposed to close the prompt dialog programatically when the user clicks on Home Button or If you had to move to next activity without user interaction
The first step is to create a Custom Spinner by extending Spinner Class.
Let's say, I have created a class called CustomSpinner in the package com.bts.sampleapp
My CustomSpinner class looks like this,
package com.bts.sampleapp;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Spinner;
public class CustomSpinner extends Spinner{
Context context=null;
public CustomSpinner(Context context) {
super(context);
this.context=context;
}
public CustomSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
}
Now in your Xml file, replace Spinner element by this custom spinner,
<com.bts.sampleapp.CustomSpinner
android:id="#+id/spin"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
The next step is to initialize and set adapter to this spinner in your Activity class,
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CustomSpinner spin=null;
spin=(CustomSpinner)findViewById(R.id.spin);
spin.setAdapter(spinnerAdapter); //you can set your adapter here.
}
The final step is to close the dialog when the user clicks on HomeButton or When the Activity moves to background. To do this, we override the onPause() like this,
#Override
protected void onPause() {
Log.i("Life Cycle", "onPause");
spin.onDetachedFromWindow();
super.onPause();
}
Now within the onPause() call the method spin.onDetachedFromWindow(); which does the job of closing the prompt dialog for you.
Now that being said, calling spin.onDetachedFromWindow(); from anywhere in your Activity should help you to close the spinner programatically. So if this is what you want, then remove the onpause().

I don't see a way to accomplish that -- there is no method on Spinner to close it. The "open" part of a Spinner is an AlertDialog on Android 1.x and 2.x, and I'm not completely sure how it is implemented on Honeycomb when using the holographic theme.
The only workaround would be to clone the source for Spinner and add in some code yourself to dismiss the dialog. But, again, it would not work on Honeycomb or higher until you can see and clone that code as well.
Beyond that, I would think that what you want is poor UX. If the user opened the Spinner, they are most likely actively examining the Spinner's contents and making a selection. Yanking that out from under their finger will confuse them, at best. Please consider an alternative approach.
Also, don't use getApplicationContext() unless you know why you are using getApplicationContext(). You do not need or even want getApplicationContext() when creating an ArrayAdapter.

I think you should scrap your use of Spinner and instead use an ImageView with a Frame Animation (i.e. <animation-list>) to create your own spinner. You just set the ImageView's background to be your Frame Animation drawable.
Then you can easily do something like this to start and stop it.

You would like to close your spinners from anywhere. Key injection for BACK pressed is the good solution but, here you are closing all the views at once.
How about setPressed(false)?
Link:
Close Spinners dropdown when two among all in a groupview are clicked simultaneously
Otherwise:
Try to make the Spinner focusable and focusableInTouchMode, and use clearFocus()
on it. Try to focus on the view below it using requestFocus() method.
Check if the spinner drop-down closes

Use the clearFocus() to close the spinner programitically
spinner.clearFocus();

Add clearfocus() in code.
Spinner spinner = (Spinner) findViewById(R.id.spinner);
spinner.clearFocus();
Use transparent background in xml
android:background="#android:color/transparent
<Spinner
android:id="#+id/spinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#android:color/transparent"
android:clickable="false"
android:focusable="?android:attr/windowOverscan"
android:focusableInTouchMode="false"
android:pointerIcon="arrow"
android:spinnerMode="dialog"
android:theme="#style/ThemeOverlay.AppCompat.Light" />

Koltin Reflection
fun AppCompatSpinner.dismiss() {
val popup = AppCompatSpinner::class.java.getDeclaredField("mPopup")
popup.isAccessible = true
val listPopupWindow = popup.get(this) as ListPopupWindow
listPopupWindow.dismiss()
}

Related

How to hide spinner dropdown android

I want to hide spinner prompt popup on outside click. If prompt popup is open and user press home key activity will minimize so when user again open application that prompt popup should disappear.
Is there any way to achieve this.
Thank You
Edit:-- Prompt popup is not customized. So I can't hide them in onPause or onResume methods.
Based on Andro's answer, you may prefer reflection to be able to call the protected method onDetachedFromWindow. Then you don't have to subclass Spinner, adapt the layout, etc.
/**
* Hides a spinner's drop down.
*/
public static void hideSpinnerDropDown(Spinner spinner) {
try {
Method method = Spinner.class.getDeclaredMethod("onDetachedFromWindow");
method.setAccessible(true);
method.invoke(spinner);
} catch (Exception e) {
e.printStackTrace();
}
}
Well its a little complicated than I thought.
I am adding the step by step details here. Try to follow it. I was able to achieve this in api level 10.
And this solution assumes that you are supposed to close the prompt dialog programatically when the user clicks on Home Button or If you had to move to next activity without user interaction
The first step is to create a Custom Spinner by extending Spinner Class.
Let's say, I have created a class called CustomSpinner in the package com.bts.sampleapp
My CustomSpinner class looks like this,
package com.bts.sampleapp;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Spinner;
public class CustomSpinner extends Spinner{
Context context=null;
public CustomSpinner(Context context) {
super(context);
this.context=context;
}
public CustomSpinner(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
}
Now in your Xml file, replace Spinner element by this custom spinner,
<com.bts.sampleapp.CustomSpinner
android:id="#+id/spin"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
The next step is to initialize and set adapter to this spinner in your Activity class,
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
CustomSpinner spin=null;
spin=(CustomSpinner)findViewById(R.id.spin);
spin.setAdapter(spinnerAdapter); //you can set your adapter here.
}
The final step is to close the dialog when the user clicks on HomeButton or When the Activity moves to background. To do this, we override the onPause() like this,
#Override
protected void onPause() {
Log.i("Life Cycle", "onPause");
spin.onDetachedFromWindow();
super.onPause();
}
Now within the onPause() call the method spin.onDetachedFromWindow(); which does the job of closing the prompt dialog for you.
Also calling spin.onDetachedFromWindow(); from anywhere within the Acitivity should close the Spinner prompt dialog if it is open.
You can popup Activity as Dialog Theme.
Override onPause method.
protected void onPause (){
super.onPause ();
this.finish();
}
spinner.clearFocus();
this is simple line to close spinner programitically

Android: Spinner item on click does't work if it is already selected

I've a Spinner with onItemSelected interation that works, but how the Api specification says:
This callback is invoked only when the newly selected position is different from the
previously selected position or if there was no selected item.
I need to remove this limitation and i want that the callback is invoked also if the user select the same element. How to do that?
Anyone did the same thing?
Any idea about this would be appreciable..
i want that the callback is invoked also if the user select the same element. How to do that?
Setting the OnItemClickListener for a Spinner will throw an exception and using ItemSelectedListener you will not be notified if the user click on the selected/same element.
I suppose the only way to overcome this limitation is to use a CustomAdapter for the Spinner items and implement the setOnClickListener for each view in the adapter.
I had this same problem and looked around for a bit. There might be multiple ways of getting this functionality to work but extending the spinner worked for me. You could do something similar to what I found here.
So instead of using the default Android spinner extend it and add some code to it that will trigger your callback method.
I would like to add that using the setOnItemClickListener on a Spinner will throw an exception as stated in the documentation:
A spinner does not support item click events. Calling this method will raise an exception.
In this case you have to make a custom spinner: Try this
public class MySpinner extends Spinner{
OnItemSelectedListener listener;
public MySpinner(Context context, AttributeSet attrs)
{
super(context, attrs);
}
#Override
public void setSelection(int position)
{
super.setSelection(position);
if (position == getSelectedItemPosition())
{
listener.onItemSelected(null, null, position, 0);
}
}
public void setOnItemSelectedListener(OnItemSelectedListener listener)
{
this.listener = listener;
}
}

How to set onClickListener() for view of Spinner?

I want to catch user interaction with a spinner like onCLickListener. Do to the 'don't call onClickListener() on AdapterView' error I found recommendations that you should override a constructer with a custom spinner to set onClickListener() on the view the spinner creates.
Tried that:
public class MySpinner extends Spinner {
public static final String TAG = "MyApp";
public MySpinner(Context context, AttributeSet attrs) {
super(context, attrs);
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(context, R.array.temp_systems, android.R.layout.simple_spinner_item);
TextView spinner_text = (TextView) findViewById(android.R.id.text1);
OnClickListener spinnerOnClickListener = new OnClickListener() {
public void onClick(View v) {
Log.d(TAG, "Should do something!");
}
};
spinner_text.setOnClickListener(spinnerOnClickListener);
setAdapter(adapter);
}
}
but when I try to include this in a layout I get a crash on failing to inflate this item.
To clarify here, onItemClickListener fires when the user clicks an item in the dropdown menu, not when the spinner is collapsed. I need to intercept after the initial spinner is clicked but before it creates the dropdown menu.
What they might mean is to Override the setOnItemClickListener and then call that in the constructor. So in your mySpinner class you would need to add: [notice it is called on ITEM click listener, that might also be part of your issue]
#Override
public void setOnItemClickListener(
android.widget.AdapterView.OnItemClickListener l) {
super.setOnItemClickListener(l);
//... do action here that you want to happen when item in spinner is clicked
}
Dunno if that will fix your issue but I hope it helps. Good Luck.
also it might be worthwhile to possibly use
public void onItemSelected(AdapterView<?> parent,
View view, int pos, long id) {
//do stuff
}
Not sure why you are needing to extend Spinnner or why you are assigning a click listener on the TextView. You should be assigning a selection listener on the spinner. As per the Spiner example consider:
1) Having a layout with a Spinner control
2) Having a 'Spinner' member of your activity
3) Inflate the layout via setContentView and then assign the spinner member via findViewById
4) Set the adapter for the spinner and call setOnItemSelectedListener on your spinner to assign a selection listener
You can use OnTouchListener instead of OnClickListener, which is not available for Spinner.

Using onClick attribute in layout xml causes a NoSuchMethodException in Android dialogs

I have created a custom dialog and a layout xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tap Me"
android:onClick="dialogClicked" />
</LinearLayout>
In the dialog class I've implemented the method "dialogClicked(View v)":
public class TestDialog extends Dialog {
public TestDialog(final Context context)
{
super(context);
}
#Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog);
}
public void dialogClicked(final View view)
{
System.out.println("clicked");
}
}
When I tap the button I get a NoSuchMethodException 'dialogClicked'. Setting the onClick handler in layout xml works fine for activities, but not in dialogs. Any ideas? What I'm doing wrong?
Define the method (dialogClicked) in Activity.
And modify TestDialog like the following code:
public class TestDialog extends Dialog {
Context mContext;
public TestDialog(final Context context)
{
super(context);
mContext=context;
}
#Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
LinearLayout ll=(LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.dialog, null);
setContentView(ll);
}
}
I think it works :)
I think the issue is one of scope. I'm not sure how'd you address this in xml, but essentially the dialogueClicked method in your layout xml doesn't know where to find the method you've defined in the dialog class.
The standard approach i've seen to bind buttons in custom layouts is as follows.
implement the OnClickListener class
Bind the buttons click event to the dialog class
Switch out the buttons in the onClick button based on id. You'd need to add an id to your button.
.
public class TestDialog extends Dialog implements android.view.View.OnClickListener
{
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.dialog);
((Button)findViewById(R.id.dialog_btn_mybutton)).setOnClickListener(this);
}
public void onClick(View view)
{
switch (view.getId())
{
case R.id.dialog_btn_mybutton:
//do stuff
// dismiss();
// cancel etc.
break;
}
}
}
Hope that helps. Would still be interested in knowing if there was a solution to using xml onClick to bind to the method. Perhaps an additional argument in the setContentView? something r'other.
I've found the following code in the View.java source:
public void onClick(View v) {
if (mHandler == null) {
try {
mHandler = getContext().getClass().getMethod(handlerName,
View.class);
...
-> The views uses its context to resolve the onclick handler method.
Noew the following code from Dialog.java source:
public Dialog(Context context, int theme) {
mContext = new ContextThemeWrapper(context, theme == 0 ? com.android.internal.R.style.Theme_Dialog : theme);
...
In the constructor of the dialog an instance of ContextThemeWrapper gets created and set as context. This instance is neither the custom dialog class, nor the calling activity, which can be the place for implementing the handler method. Therefore views are not able to find the onclick handler method.
But I have to use the onclick XML attribut. Any workarounds available?
Dialogs need the signature
dialogClicked(DialogInterface dialog, int id) { ... }
android:onClick="method" is pretty cool, but it doesn't work on Android 1.5 so I am avoiding for some time.
An easy workaround:
Make your Dialog an Activity and use android:theme="#android:style/Theme.Dialog" in you AndroidManifest.
Following on from Jett Hsieh's post, I've implemented my dialogs slightly differently using showDialog and dismissDialog, but the fundamentals of getting the android:onClick working have been the same, my example code is below for future reference.
public class ExampleActivity extends Activity {
static final int DIALOG_DISCLAIMER = 0;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
showDialog(DIALOG_DISCLAIMER);
}
protected Dialog onCreateDialog(int id)
{
Dialog dialog;
switch(id)
{
case DIALOG_DISCLAIMER:
dialog = new Dialog(this);
dialog.setContentView(R.layout.main_disclaimer);
LinearLayout ll = (LinearLayout) LayoutInflater.from(this).inflate(R.layout.main_disclaimer, null);
dialog.setContentView(ll);
break;
default:
dialog = null;
}
return dialog;
}
public void onClick(View v)
{
switch(v.getId())
{
case R.id.maindisclaimer_button_accept:
dismissDialog(DIALOG_DISCLAIMER);
break;
}
}
}
And the layout file:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="#+id/linearLayout1"
android:padding="10dp"
android:orientation="vertical"
android:background="#drawable/roundedcorners">
<Button
android:id="#+id/maindisclaimer_button_accept"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="#string/string_accept"
android:onClick="onClick" >
</Button>
</LinearLayout>
Try to define that method (dialogClicked) in the activity and not in the dialog.
It might use reflection so if you use different activities just write that method in each activity that might show that dialog
A dialog is always created and displayed as part of an Activity. According to Android References:
If you decide to create a dialog outside of the onCreateDialog() method,
it will not be attached to an Activity. You can, however,
attach it to an Activity with setOwnerActivity(Activity).
Also, are you passing the object returned by getApplicationContext(); to the constructor of TestDialog?
system looks for the method in the where the layout has been inflated from, or in the activity class to which the xml was set as content.

Android Spinner selection

The OnItemSelectedListener event handler gets called both when a spinner
selection is changed programmatically, and when a user physically clicks the spinner control.
Is is possible to determine if an event was triggered by a user
selection somehow?
Or is there another way to handle spinner user selections?
To workaround you need to remember the last selected position. Then inside of your spinner listener compare the last selected position with the new one. If they are different, then process the event and also update the last selected position with new position value, else just skip the event processing.
If somewhere within the code you are going to programatically change spinner selected position and you don't want the listener to process the event, then just reset the last selected position to the one you're going to set.
Yes, Spinner in Android is painful. I'd even say pain starts from its name - "Spinner". Isn't it a bit misleading? :) As far as we're talking about it you should also be aware there's a bug - Spinner may not restore (not always) its state (on device rotation), so make sure you handle Spinner's state manually.
Hard to believe that a year and a half later, the problem still exists and continues to boggle people...
Thought I'd share the workaround I came up with after reading Arhimed's most useful post (thanks, and I agree about spinners being painful!). What I've been doing to avoid these false positives is to use a simple wrapper class:
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
public class OnItemSelectedListenerWrapper implements OnItemSelectedListener {
private int lastPosition;
private OnItemSelectedListener listener;
public OnItemSelectedListenerWrapper(OnItemSelectedListener aListener) {
lastPosition = 0;
listener = aListener;
}
#Override
public void onItemSelected(AdapterView<?> aParentView, View aView, int aPosition, long anId) {
if (lastPosition == aPosition) {
Log.d(getClass().getName(), "Ignoring onItemSelected for same position: " + aPosition);
} else {
Log.d(getClass().getName(), "Passing on onItemSelected for different position: " + aPosition);
listener.onItemSelected(aParentView, aView, aPosition, anId);
}
lastPosition = aPosition;
}
#Override
public void onNothingSelected(AdapterView<?> aParentView) {
listener.onNothingSelected(aParentView);
}
}
All it does is trap item selected events for the same position that was already selected (e.g. the initial automatically triggered selection for position 0), and pass on other events to the wrapped listener. To use it, all you have to do is modify the line in your code that calls the listener to include the wrapper (and add the closing bracket of course), so instead of, say:
mySpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
...
});
you'd have this:
mySpinner.setOnItemSelectedListener(new OnItemSelectedListenerWrapper(new OnItemSelectedListener() {
...
}));
Obviously once you've tested it, you could get rid of the Log calls, and you could add the ability to reset the last position if required (you'd have to keep a reference to the instance, of course, rather than declaring on-the-fly) as Arhimed said.
Hope this can help someone from being driven crazy by this strange behaviour ;-)
In the past I've done things like this to distinguish
internal++; // 'internal' is an integer field initialized to 0
textBox.setValue("...."); // listener should not act on this internal setting
internal--;
Then in textBox's listener
if (internal == 0) {
// ... Act on user change action
}
I use ++ and -- rather than setting a boolean value to 'true' so that there is no worry when methods nest other methods that might also set the internal change indicator.
I had this situation lately when using spinners and the internet didn't came up with a suitable solution.
My application scenario:
X spinners (dynamically, 2 for each cpu, min & max) for setting & viewing the CPU-Frequency. They are filled when the application starts and they also get the current max/min freq of the cpu set. A thread runs in the background and checks for changes every second and updates the spinners accordingly. If a new frequency inside the spinner is set by the user the new frequency is set.
The issue was that the thread accessed setSelection to update the current frequency which in turn called my listener and I had no way of knowing if it was the user or the thread that changed the value. If it was the thread I didn't want the listener to be called since there would have been no need to change the frequency.
I came up with a solution that suits my needs perfectly and works around the listener on your call :) (and I think this solution gives you maximal control)
I extended Spinner:
import android.content.Context;
import android.widget.Spinner;
public class MySpinner extends Spinner {
private boolean call_listener = true;
public MySpinner(Context context) {
super(context);
}
public boolean getCallListener() {
return call_listener;
}
public void setCallListener(boolean b) {
call_listener = b;
}
#Override
public void setSelection(int position, boolean lswitch) {
super.setSelection(position);
call_listener = lswitch;
}
}
and created my own OnItemSelectedListener:
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
public class SpinnerOnItemSelectedListener implements OnItemSelectedListener {
public void onItemSelected(AdapterView<?> parent, View view, int pos,long id) {
MySpinner spin = (MySpinner) parent.findViewById(parent.getId());
if (!spin.getCallListener()) {
Log.w("yourapptaghere", "Machine call!");
spin.setCallListener(true);
} else {
Log.w("yourapptaghere", "UserCall!");
}
}
#Override
public void onNothingSelected(AdapterView<?> arg0) {
// TODO Auto-generated method stub
}
}
If you now create a MySpinner you can use this to set the selection:
setSelection(position, callListener);
Where callListener is either true or false. True will call the listener and is default, which is why user interactions are getting identified, false will also call the listener but uses code you want for this special case, exempli gratia in my case: Nothing.
I hope that someone else finds this useful and is spared a long journey to look if something like this already exists :)
I also looked for a good solution on the internet but didn't find any that satisfied my needs.
So I've written this extension on the Spinner class so you can set a simple OnItemClickListener, which has the same behaviour as a ListView.
Only when an item gets 'selected', the onItemClickListener is called.
Have fun with it!
public class MySpinner extends Spinner
{
private OnItemClickListener onItemClickListener;
public MySpinner(Context context)
{
super(context);
}
public MySpinner(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public MySpinner(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
#Override
public void setOnItemClickListener(android.widget.AdapterView.OnItemClickListener inOnItemClickListener)
{
this.onItemClickListener = inOnItemClickListener;
}
#Override
public void onClick(DialogInterface dialog, int which)
{
super.onClick(dialog, which);
if (this.onItemClickListener != null)
{
this.onItemClickListener.onItemClick(this, this.getSelectedView(), which, this.getSelectedItemId());
}
}
}
Just to expand on aaamos's post above, since I don't have the 50 rep points to comment, I am creating a new answer here.
Basically, his code works for the case when the initial Spinner selection is 0. But to generalize it, I amended his code the following way:
#Override
public void setOnItemSelectedListener(final OnItemSelectedListener listener)
{
if (listener != null)
super.setOnItemSelectedListener(new OnItemSelectedListener()
{
private static final int NO_POSITION = -1;
private int lastPosition = NO_POSITION;
#Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id)
{
if ((lastPosition != NO_POSITION) && (lastPosition != position))
listener.onItemSelected(parent, view, position, id);
lastPosition = position;
}
#Override
public void onNothingSelected(AdapterView<?> parent)
{
listener.onNothingSelected(parent);
}
});
else
super.setOnItemSelectedListener(null);
}
Basically, this code will ignore the very first firing of onItemSelected(), and then all subsequent "same position" calls.
Of course, the requirement here is that the selection is set programatically, but that should be the case anyhow if the default position is not 0.
I did some logging and discovered that it only ever gets called on initialize, which is annoying. Can't see the need for all this code, I just created an instance variable that was initialised to a guard value, and then set it after the method had been called the first time.
I logged when the onItemSelected method was being called it was otherwise only being called once.
I had a problem where it was creating two of something and realised it was because I was calling add() on my custom adapter, which already had a reference to the list I was referencing and had added to outside the adapter. After I realised this and removed the add method the problem went away.
Are you guys sure you need all this code?
I know this is pretty late, but I came up with a very simple solution to this. It is based on Arhimed's answer, it's exactly the same. It's very easy to implement too. Refer the accepted answer:
Undesired onItemSelected calls

Categories

Resources