0

I'm developing an android app which contains an expandable listview and a search bar at the top. So if I type anything into the edit textfield i want that it filters the expandable list.

For example: I type : "as" into the search bar --> the list should only display entries like: "assert","base","case","assembling", etc..

I have searched several hours on the internet but I'm not able to implement this feature. So I really hope you can help me (:

Here is my Expandable List Adapter:

package my.pack;

public class ExpandableListAdapter extends BaseExpandableListAdapter {

    @Override
    public boolean areAllItemsEnabled() {
        return true;
    }

    private Context context;
    private ArrayList<String> groups;
    private ArrayList<ArrayList<Product>> children;

    public ExpandableListAdapter(Context context, ArrayList<String> groups,
            ArrayList<ArrayList<Product>> children) {
        this.context = context;
        this.groups = groups;
        this.children = children;
    }

    public void addItem(Product product) {
        if (!groups.contains(product.getGroup())) {
            groups.add(product.getGroup());
        }
        int index = groups.indexOf(product.getGroup());
        if (children.size() < index + 1) {
            children.add(new ArrayList<Product>());
        }
        children.get(index).add(product);

    }

    public Object getChild(int groupPosition, int childPosition) {
        return children.get(groupPosition).get(childPosition);
    }

    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    // Return a child view. You can load your custom layout here.

    public View getChildView(int groupPosition, int childPosition,
            boolean isLastChild, View convertView, ViewGroup parent) {
        Product product = (Product) getChild(groupPosition, childPosition);
        if (convertView == null) {
            LayoutInflater infalInflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = infalInflater.inflate(R.layout.productinsertchild,
                    null);
        }
        TextView tv = (TextView) convertView.findViewById(R.id.tvChild);
        tv.setText("   " + product.getpName());

        return convertView;
    }

    public int getChildrenCount(int groupPosition) {
        return children.get(groupPosition).size();
    }

    public Object getGroup(int groupPosition) {
        return groups.get(groupPosition);
    }

    public int getGroupCount() {
        return groups.size();
    }

    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    // Return a group view. You can load your custom layout here.

    public View getGroupView(int groupPosition, boolean isExpanded,
            View convertView, ViewGroup parent) {
        String group = (String) getGroup(groupPosition);
        if (convertView == null) {
            LayoutInflater infalInflater = (LayoutInflater) context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = infalInflater.inflate(R.layout.productinsertgroup,
                    null);
        }
        TextView tv = (TextView) convertView.findViewById(R.id.tvGroup);
        tv.setText(group);
        return convertView;
    }

    public boolean hasStableIds() {
        return true;
    }

    public boolean isChildSelectable(int arg0, int arg1) {
        return true;
    }

}

And here my Activity: Note that the ExpandableListView gets data from a online mysql server. Thats the reason why I'm using async task.

package activities.shop;

public class ProductInsert extends BaseActivity {

    public static final String phpServerConnection = "url-to-php-file";
    public static final String phpgetGrocery = "url-to-php-file";

    static final int MY_DIALOG_ID = 0;
    protected static AppPreferences appPrefs;
    private getGroceryTask ggt = null;

    private ExpandableListAdapter adapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        ExpandableListView listView = (ExpandableListView) findViewById(R.id.listView);

        listView.setOnChildClickListener(new OnChildClickListener() {

            public boolean onChildClick(ExpandableListView arg0, View arg1,
                    int arg2, int arg3, long arg4) {
                Toast.makeText(getBaseContext(), "Child clicked",
                        Toast.LENGTH_LONG).show();
                return false;
            }
        });

        listView.setOnGroupClickListener(new OnGroupClickListener() {

            public boolean onGroupClick(ExpandableListView arg0, View arg1,
                    int arg2, long arg3) {
                return false;
            }
        });

        adapter = new ExpandableListAdapter(this, new ArrayList<String>(),
                new ArrayList<ArrayList<Product>>());

        // Set this blank adapter to the list view
        listView.setAdapter(adapter);

        ggt = new getGroceryTask(this);
        ((getGroceryTask) ggt).execute();

    }

    @Override
    public int getContentViewId() {

        return R.layout.productinsert;
    }

    @Override
    protected Dialog onCreateDialog(int id) {

        ProgressDialog progressDialog = null;

        switch (id) {
        case MY_DIALOG_ID:
            progressDialog = new ProgressDialog(this);
            progressDialog.setMessage("Aktualisieren...");

            break;
        default:
            progressDialog = null;
        }

        return progressDialog;
    }

    final static class getGroceryTask extends
            SuperAsyncTask<String, String, Void> {

        ProductInsert activity;
        InputStream is = null;
        String result = "";

        public getGroceryTask(BaseActivity activity) {

            super(activity, MY_DIALOG_ID); // change your dialog ID here...
            this.activity = (ProductInsert) activity; // and your dialog will be
                                                        // managed
                                                        // automatically!
        }

        @Override
        protected Void doInBackground(String... params) {

            appPrefs = new AppPreferences(activity);

            ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
            nameValuePairs.add(new BasicNameValuePair("uEmail", appPrefs
                    .getUserEmail()));

            try {
                HttpClient httpclient = new DefaultHttpClient();
                HttpPost httppost = new HttpPost(phpgetGrocery);
                httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                HttpResponse response = httpclient.execute(httppost);
                HttpEntity entity = response.getEntity();
                is = entity.getContent();

            } catch (Exception e) {
                Log.e("log_tag", "Error in http connection " + e.toString());
            }

            // convert response to string
            try {
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(is, "UTF-8"), 8);
                StringBuilder sb = new StringBuilder();
                String line = null;
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "\n");
                }
                is.close();
                result = sb.toString();

            } catch (Exception e) {
                Log.e("log_tag", "Error converting result " + e.toString());
            }

            return null;
        }

        private Product get(int pid, String pName, String pKat) {
            return new Product(pid, pName, pKat);
        }

        @Override
        public void onAfterExecute() {

            try {

                JSONArray jArray = new JSONArray(result);
                for (int i = 0; i < jArray.length(); i++) {

                    JSONObject json_data = jArray.getJSONObject(i);

                    activity.adapter.addItem(get(json_data.getInt("pid"),
                            json_data.getString("pName"),
                            json_data.getString("pKat")));

                }

                activity.adapter.notifyDataSetChanged();

            } catch (JSONException e) {
                Log.e("log_tag", "Error parsing datauuuuuu " + e.toString());

            }
        }

    }

}
Yash
  • 3
  • 1
  • 2

2 Answers2

0

You might consider extending from CursorTreeAdapter instead of BaseExpandableListAdapter - that way you can override getFilterQueryProvider (and provide your own FilterQueryProvider) for the functionality you're looking for. Granted, this means you'll have to translate the results from your MySQL DB into a cursor, but if you do the filtering process gets much easier.

Otherwise, you have to override getFilter() and provide your own Filter in the ListAdapter - this isn't too different - it has some more complications to it, but you wouldn't have to add the cursor translation layer.

in any case, add your own textChangedListener to the filter edit text to make calls to the filter.

JRaymond
  • 11,339
  • 5
  • 35
  • 39
  • I'm doing similar [here](http://stackoverflow.com/questions/20585273/cursortreeadapter-with-search-implementation) with [`FilterQueryProvider`](http://developer.android.com/reference/android/widget/FilterQueryProvider.html). Only I don't know what I should do in `runQuery()` when I've multiple cursors that represents a child of [`CursorTreeAdapter`](http://developer.android.com/reference/android/widget/CursorTreeAdapter.html). Could you help me with this? – user2784435 Jan 13 '14 at 13:02
0

The problem with Expandable List View is that it takes time if you are having many children associated with the group parents....

You can rather use an AutoCompleteTextView with pre-populated items of your expandable listview so that you can have smooth functionality of search and allow the list to be refreshed based on user selection instead of the above mentioned functionality...You might affect the end user experience with your above mentioned functionality....But if you are so persistent on your implementation..You can use the same AutoCompleteTextView with onKeyDown functionality or textvalidation functionality...

Have a look at the widget http://developer.android.com/reference/android/widget/AutoCompleteTextView.html

Ananth
  • 961
  • 9
  • 23