Spinner with sub-spinner not working as expected

I have two spinners, such that my second spinner changes options that it can offer according to the item selected in the first spinner. Easy?

Example: If I select 'a' in main spinner, the sub spinner should show 'a1' as option. If I select 'b' in main spinner, the sub spinner should show 'b1','b2' as options. If I select 'c' in main spinner, the sub spinner should show 'c1','c2','c3' as options.

I use a library called SearchableSpinner but that does not matter as it works just like the Android spinner.

public class PostComplaint extends AppCompatActivity {
    String[] problems_main = {"a","b","c"};
    String[][] problems_sub = {{"a1"},{"b1","b2"},{"c1","c2","c3"}};

    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_post_complaint);

    spinner_main = (SearchableSpinner)findViewById(R.id.spinner_main);
    spinner_sub = (SearchableSpinner) findViewById(R.id.spinner_sub);

    ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, problems_main);
    spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner_main.setAdapter(spinnerAdapter);
    spinnerAdapter.notifyDataSetChanged();

    spinner_main.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
            setSubSpinner(position);
        }
        @Override
        public void onNothingSelected(AdapterView<?> parent) {
            Toast.makeText(PostComplaint.this, "Nothing selected", Toast.LENGTH_SHORT).show();
        }
    });
}

void setSubSpinner(int i){
    String[] myArray = problems_sub[i]; //Note: problems_sub is a two dimensional array
    ArrayAdapter<String> spinnerAdapter_sub = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, myArray);
    spinnerAdapter_sub.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner_sub.setAdapter(spinnerAdapter_sub);
    spinnerAdapter_sub.notifyDataSetChanged();
}

Problem: Whichever item I click on the main spinner for the first time, according to that the sub spinner is selected. Then if I change the main spinner, the sub spinner is not changing.

The question is open for suggestions. Comment if it is not understandable.

Answers


The error is coming because of the following function in the SearchableSpinner Class:

@Override
public boolean onTouch(View v, MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        ArrayAdapter adapter = (ArrayAdapter) getAdapter();

        if (null != adapter) {

            if (_items.size() == 0) {
                for (int i = 0; i < adapter.getCount(); i++) {
                    _items.add(adapter.getItem(i));
                }
            }
            SearchableListDialog searchableListDialog = SearchableListDialog.newInstance
                    (_items);
            searchableListDialog.setOnSearchableItemClickListener(this);
            searchableListDialog.show(((Activity) _context).getFragmentManager(), "TAG");
        }
    }
    return true;
}

The condition if(_items.size() == 0) becomes true only the first time you click on the sub spinner and hence it gets initialized correctly and you will see correct values. However, once you have clicked on the sub spinner, _item.size() will never be zero and thus, the updated sub spinner values will never be rendered.

I suggest you use the default Android Spinner or fork the repository and fix the error and use the same.

EDIT

You can try using this class:

import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Spinner;

import com.toptoche.searchablespinnerlibrary.SearchableListDialog;

import java.util.ArrayList;
import java.util.List;

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

private Context _context;
private List _items;
private boolean isDataSetChanged;

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

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

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

private void init() {
    _items = new ArrayList();
    setOnTouchListener(this);
}

@Override
public boolean onTouch(View v, MotionEvent event) {
    if (event.getAction() == MotionEvent.ACTION_DOWN) {
        ArrayAdapter adapter = (ArrayAdapter) getAdapter();

        if (null != adapter) {

            if (isDataSetChanged) {
                if(_items.size() != 0) {
                    _items = new ArrayList();
                }
                for (int i = 0; i < adapter.getCount(); i++) {
                    _items.add(adapter.getItem(i));
                }
                isDataSetChanged = false;
            }
            SearchableListDialog searchableListDialog = SearchableListDialog.newInstance
                    (_items);
            searchableListDialog.setOnSearchableItemClickListener(this);
            searchableListDialog.show(((Activity) _context).getFragmentManager(), "TAG");
        }
    }
    return true;
}

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

public void notifyDataChanged(Boolean hasDataChanged) {
    this.isDataSetChanged = hasDataChanged;
}
}

Also, update your layout file and PostComplaint Class to use CustomSearchableSpinner in place of Searchable Spinner. It may not be the best approach, but it works.

EDIT 2

You will need to call spinnerAdapter_sub.notifyDataChanged(true) after you call spinnerAdapter_sub.notifyDataSetChanged();.


Need Your Help

I upgraded Knockout.js, now my templates are broken

javascript knockout.js

I upgraded knockout.js from 1.2 to 2.1 in my project. I'm using some basic templates and they seem to be broken. I am including jQuery.tmpl.js and knockout-2.1.0.js. Hoping for a quick answer.

Filtering nested objects in elasticsearch 2.2 not working

elasticsearch

I've read some articles and documentation about queries/filters in nested objects but I can not make this sample work. Hopefully you can help me to check what is wrong. Bellow is the index and mapp...