Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spinner Crashed!!!! #48

Open
anand2693 opened this issue Mar 30, 2017 · 14 comments
Open

Spinner Crashed!!!! #48

anand2693 opened this issue Mar 30, 2017 · 14 comments

Comments

@anand2693
Copy link

When I click the SearchableSinner throw Exception

java.lang.IllegalStateException: Fragment already added: SearchableListDialog{ad4f6610 #0 TAG}
at android.app.FragmentManagerImpl.addFragment(FragmentManager.java:1133)
at android.app.BackStackRecord.run(BackStackRecord.java:618)
at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1447)
at android.app.FragmentManagerImpl$1.run(FragmentManager.java:443)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5017)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
at dalvik.system.NativeStart.main(Native Method)

@usherjc
Copy link

usherjc commented May 23, 2017

the same as you

@anand2693
Copy link
Author

I solved the issue!
Just add this lines in your Activity class

@OverRide
public void onAttachFragment(Fragment fragment) {
if (fragment.isAdded())
return;
super.onAttachFragment(fragment);
}

@usherjc
Copy link

usherjc commented May 23, 2017

@anand2693 thank bro

@usherjc
Copy link

usherjc commented May 23, 2017

@anand2693 and...could u write the reason here to explain why the crash happend?

@ashwindmk
Copy link

ashwindmk commented Jun 15, 2017

Unfortunately, the above solution by anand2693 did not solve the crash for me. The crash occurs when I double click on the spinner before the dialog opened. So I had to create my own custom searchable spinner which extends searchable spinner:

CustomSearchableSpinner.java:

public class CustomSearchableSpinner extends SearchableSpinner {

     public static boolean isSpinnerDialogOpen = false;

     public CustomSearchableSpinner(Context context) {
         super(context);
     }

     public CustomSearchableSpinner(Context context, AttributeSet attrs) {
         super(context, attrs);
     }

     public CustomSearchableSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
     }

     @Override
     public boolean onTouch(View v, MotionEvent event) {
         if (event.getAction() == MotionEvent.ACTION_UP) {
             if (!isSpinnerDialogOpen) {
                 isSpinnerDialogOpen = true;
                 return super.onTouch(v, event);
             }
             isSpinnerDialogOpen = false;
         }
         new Handler().postDelayed(new Runnable() {
             @Override
             public void run() {
                 isSpinnerDialogOpen = false;
             }
         }, 500);
         return true;
     }
 }

Now in your activity inside OnItemSelectedListener set the isSpinnerDialogOpen variable to false.

myCustomSearchableSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            myCustomSearchableSpinner.isSpinnerDialogOpen = false;
            ...
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            myCustomSearchableSpinner.isSpinnerDialogOpen = false;
            ...
        }
    });

You can see the working example of above code in my repository: Searchable Spinner

@carloscte
Copy link

@ashwindmk I really enjoyed your solution! By using it, I was able to make some adjustments in which the stability and the operation were further improved. Take a look...

CustomSearchableSpinner.java

public class CustomSearchableSpinner extends SearchableSpinner {
     private boolean isSpinnerDialogOpen = false;
     private Timer waitTimer;

     public CustomSearchableSpinner(Context context) {
         super(context);
     }

     public CustomSearchableSpinner(Context context, AttributeSet attrs) {
         super(context, attrs);
     }

     public CustomSearchableSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
     }

     public void setIsSpinnerDialogOpen(Boolean value){
         this.isSpinnerDialogOpen = value;
     }

     @Override
     public boolean onTouch(View v, MotionEvent event) {
         if (event.getAction() == MotionEvent.ACTION_UP) {
             if (!isSpinnerDialogOpen) {
                 setIsSpinnerDialogOpen(true);
                 return super.onTouch(v, event);
             }
         }

         if(waitTimer != null){
             waitTimer.cancel();
         } 
         
         temporizador();
         return true;
     }

     private void temporizador(){
         waitTimer = new Timer();
         waitTimer.schedule(new TimerTask() {
             @Override
             public void run() {
                 setIsSpinnerDialogOpen(false);
             }
         }, 200);
     }
 }

inside OnItemSelectedListener...

myCustomSearchableSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            myCustomSearchableSpinner.isSpinnerDialogOpen = false;
            ...
        }

        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            myCustomSearchableSpinner.isSpinnerDialogOpen = false;
            ...
        }
    });

@ZeeOne
Copy link

ZeeOne commented Jul 26, 2017

Thanks guys! This is great! I modified it a bit so that you do not have to set the isSpinnerDialogOpen=false every time (I hope it works well, I'm still a bit of a noob with Android):

`

public class TestSpinner extends SearchableSpinner {

public static boolean isSpinnerDialogOpen = false;

public TestSpinner(Context context) {
    super(context);
}

public TestSpinner(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public TestSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
}

private static final long MIN_DELAY_MS = 500;

private long mLastClickTime;


@Override
public boolean onTouch(View v, MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_UP) {

        long lastClickTime = mLastClickTime;
        long now = System.currentTimeMillis();
        mLastClickTime = now;
        if (now - lastClickTime < MIN_DELAY_MS) {
            // Too fast: ignore
           return true;
        } else {
            // Register the click
            return super.onTouch(v, event);
        }
    }
    return true;
}

}`

@MindNotion
Copy link

On multiple times click on spinner the app crash.
In SearchableSpinner.java line number 91 change _searchableListDialog.show(scanForActivity(_context).getFragmentManager(), "TAG"); code to

if(!_searchableListDialog.isAdded()) {
_searchableListDialog.show(scanForActivity(_context).getFragmentManager(), "TAG");
}

the issue will resolved

@Johnett
Copy link

Johnett commented Dec 19, 2017

@MindNotion
You saved my day. I tried all the other solutions but if we repeatedly click on the spinner app will crash eventually. But after adding this fix it never crashed. Thanks again.
Note to developers:- You should add this fix to the library ASAP.

@padmajarani
Copy link

@MindNotion
how to add to that code to the library .. it is locked

@sousasj
Copy link

sousasj commented Apr 23, 2019

@MindNotion First you need to extract the searchablespinnerlibrary-1.3.1-sources.jar file, edit the SearchableSpinner.java file at the line 91 and replace it with this code
if (!_searchableListDialog.isAdded()) { _searchableListDialog.dismiss(); _searchableListDialog.show(scanForActivity(_context).getFragmentManager(), "TAG"); } else { _searchableListDialog.dismiss(); _searchableListDialog.show(scanForActivity(_context).getFragmentManager(), "TAG"); }

@mohdqasim
Copy link

mohdqasim commented May 15, 2022

@MindNotion why you not raise PR for this fix? as this fixed the bug

@CodingByDay
Copy link

Here is my solution for our Xamarin.Android application in C#.

using Android.Content;
using Android.OS;
using Android.Util;
using Android.Views;
using Com.Toptoche.Searchablespinnerlibrary;
using Java.Lang;
using Java.Util.Jar;
using System;
using System.Threading.Tasks;
using System.Timers;

public class CustomSearchableSpinner : SearchableSpinner
{

public static bool isSpinnerDialogOpen = false;

private Timer timer;

public CustomSearchableSpinner(Context context) : base(context)
{
}
public CustomSearchableSpinner(Context context, IAttributeSet attrs, int defStyleAttr): base(context, attrs, defStyleAttr)
{

}
public CustomSearchableSpinner(Context context, IAttributeSet attrs): base (context, attrs) 
{

}

public override bool OnTouch(View v, MotionEvent motion)
{
    if(isSpinnerDialogOpen) { return true; } 
    else if(motion.Action == MotionEventActions.Up)
    {
        if(!isSpinnerDialogOpen)
        {
            isSpinnerDialogOpen = true;
            PostDelayed(DefaultDialogValue, 500);
            return base.OnTouch(v, motion);
        }
    }
    return true;
}

Action DefaultDialogValue = new Action(() => {

    isSpinnerDialogOpen = false;

});

}

@habibTeck
Copy link

use this class and every thing will work fine for you

public class CustomSearchableSpinner extends Spinner implements View.OnTouchListener,
SearchableListDialog.SearchableItem {

public static final int NO_ITEM_SELECTED = -1;
private Context _context;
private List _items;
private SearchableListDialog _searchableListDialog;

private boolean _isDirty;
private ArrayAdapter _arrayAdapter;
private String _strHintText;
private boolean _isFromInit;

public CustomSearchableSpinner(Context context) {
    super(context);
    this._context = context;
    init();
}

public CustomSearchableSpinner(Context context, AttributeSet attrs) {
    super(context, attrs);
    this._context = context;
    TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SearchableSpinner);
    final int N = a.getIndexCount();
    for (int i = 0; i < N; ++i) {
        int attr = a.getIndex(i);
        if (attr == R.styleable.SearchableSpinner_hintText) {
            _strHintText = a.getString(attr);
        }
    }
    a.recycle();
    init();
}

public CustomSearchableSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    this._context = context;
    init();
}

private void init() {
    _items = new ArrayList();
    _searchableListDialog = SearchableListDialog.newInstance
            (_items);
    _searchableListDialog.setOnSearchableItemClickListener(this);
    setOnTouchListener(this);

    _arrayAdapter = (ArrayAdapter) getAdapter();
    if (!TextUtils.isEmpty(_strHintText)) {
        ArrayAdapter arrayAdapter = new ArrayAdapter(_context, android.R.layout
                .simple_list_item_1, new String[]{_strHintText});
        _isFromInit = true;
        setAdapter(arrayAdapter);
    }
}

@Override
public boolean onTouch(View v, MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_UP) {

        if (null != _arrayAdapter) {

            // Refresh content #6
            // Change Start
            // Description: The items were only set initially, not reloading the data in the
            // spinner every time it is loaded with items in the adapter.
            _items.clear();
            for (int i = 0; i < _arrayAdapter.getCount(); i++) {
                _items.add(_arrayAdapter.getItem(i));
            }
            // Change end.

            if(!_searchableListDialog.isAdded()) {
                _searchableListDialog.show(scanForActivity(_context).getFragmentManager(), "TAG");
            }
        }
    }
    return true;
}

@Override
public void setAdapter(SpinnerAdapter adapter) {

    if (!_isFromInit) {
        _arrayAdapter = (ArrayAdapter) adapter;
        if (!TextUtils.isEmpty(_strHintText) && !_isDirty) {
            ArrayAdapter arrayAdapter = new ArrayAdapter(_context, android.R.layout
                    .simple_list_item_1, new String[]{_strHintText});
            super.setAdapter(arrayAdapter);
        } else {
            super.setAdapter(adapter);
        }

    } else {
        _isFromInit = false;
        super.setAdapter(adapter);
    }
}

@Override
public void onSearchableItemClicked(Object item, int position) {
    setSelection(_items.indexOf(item));

    if (!_isDirty) {
        _isDirty = true;
        setAdapter(_arrayAdapter);
        setSelection(_items.indexOf(item));
    }
}

public void setTitle(String strTitle) {
    _searchableListDialog.setTitle(strTitle);
}

public void setPositiveButton(String strPositiveButtonText) {
    _searchableListDialog.setPositiveButton(strPositiveButtonText);
}

public void setPositiveButton(String strPositiveButtonText, DialogInterface.OnClickListener onClickListener) {
    _searchableListDialog.setPositiveButton(strPositiveButtonText, onClickListener);
}

public void setOnSearchTextChangedListener(SearchableListDialog.OnSearchTextChanged onSearchTextChanged) {
    _searchableListDialog.setOnSearchTextChangedListener(onSearchTextChanged);
}

private Activity scanForActivity(Context cont) {
    if (cont == null)
        return null;
    else if (cont instanceof Activity)
        return (Activity) cont;
    else if (cont instanceof ContextWrapper)
        return scanForActivity(((ContextWrapper) cont).getBaseContext());

    return null;
}

@Override
public int getSelectedItemPosition() {
    if (!TextUtils.isEmpty(_strHintText) && !_isDirty) {
        return NO_ITEM_SELECTED;
    } else {
        return super.getSelectedItemPosition();
    }
}

@Override
public Object getSelectedItem() {
    if (!TextUtils.isEmpty(_strHintText) && !_isDirty) {
        return null;
    } else {
        return super.getSelectedItem();
    }
}

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests