Adrian Olar
Adrian Olar

Reputation: 2903

ListView filtering issue Android

I am trying to add a search textfield to my listview in order to do some filtering and my list adapter uses a custom object rather than a simple String. The search seems to working at first glance, but the adapter does not update if i delete the filtering string.

Below is what i have tried:

This is my custom ArrayAdapter:

    public class ArticolAdapter extends OrderManagerAdapter<Articol> implements Scrollable {
    private List<Articol> orderList;
    private final LayoutInflater inflater;
    private final Context context;

    public ArticolAdapter(Context context, List<Articol> objects) {
        super(context, objects);
        this.inflater = LayoutInflater.from(context);
        this.orderList = objects;
        this.context = context;
    }

    @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder;
        if (convertView == null) {
            convertView = inflater.inflate(R.layout.item_articol, parent, false);
            holder = new ViewHolder();

            holder.name = (TextView) convertView.findViewById(R.id.numeTV);
            holder.deLivrat = (TextView) convertView.findViewById(R.id.de_livrat);
            holder.articolPoza = (ImageView) convertView.findViewById(R.id.pictureCategory);
            holder.observatiiTV = (TextView) convertView.findViewById(R.id.observatii);
            holder.incarcatTV = (TextView) convertView.findViewById(R.id.incarcat);
            holder.background = (RelativeLayout) convertView.findViewById(R.id.expandable_toggle_button);

            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        final Articol articol = getItem(position);
        holder.name.setText(articol.getNume());
        System.out.println(articol.getNume());
        holder.deLivrat.setText("De livrat: " + Constants.DF.format(articol.getComandat()));
        holder.incarcatTV.setText("Incarcat: " + fmt(articol.getIncarcat()));
        holder.observatiiTV.setText("Observatii: " + articol.getObservatii());
        holder.background.setPadding(5, 5, 5, 5);
        if (articol.getComandat() == articol.getIncarcat()) {
            holder.background.setBackground(context.getResources().getDrawable(R.drawable.list_item_completed));
        } else {
            holder.background.setBackground(context.getResources().getDrawable(R.drawable.list_item_bg));
        }
        return convertView;
    }

    public static String fmt(double d) {
        if (d == (int) d)
            return String.format("%d", (int) d);
        else
            return String.format("%s", d);
    }

    @Override
    public String getIndicatorForPosition(int childposition, int groupposition) {
        return Character.toString(orderList.get(childposition).getNume().charAt(0));
    }

    @Override
    public int getScrollPosition(int childposition, int groupposition) {
        return childposition;
    }

    private class ViewHolder {
        private TextView name, deLivrat, observatiiTV, incarcatTV;
        private ImageView articolPoza;
        private RelativeLayout background;
    }

    private List<Articol> orig;

    @Override
    public Filter getFilter() {
        return new Filter() {
            @Override
            protected FilterResults performFiltering(CharSequence constraint) {
                final FilterResults oReturn = new FilterResults();
                final ArrayList<Articol> results = new ArrayList<Articol>();
                if (orig == null) {
                    orig = orderList;
                }
                if (constraint != null) {
                    if (orig != null && orig.size() > 0) {
                        for (final Articol g : orig) {
                            if (g.getNume().toLowerCase()
                                    .contains(constraint.toString())) {
                                results.add(g);
                            }
                        }
                    }
                    oReturn.values = results;
                }
                return oReturn;
            }

            @SuppressWarnings("unchecked")
            @Override
            protected void publishResults(CharSequence constraint,
                                          FilterResults results) {
                orderList = (ArrayList<Articol>) results.values;
                notifyDataSetChanged();
                clear();
                for (Articol anOrderList : orderList) {
                    add(anOrderList);
                }
                notifyDataSetInvalidated();
            }
        };
    }

}

The OrderManagerAdapter:

public class OrderManagerAdapter<T> extends ArrayAdapter<T> {

    private final List<T> objects;
    private final Object mLock;

    public OrderManagerAdapter(Context context) {
        super(context, 0);
        objects = new ArrayList<T>();
        mLock = new Object();
        setNotifyOnChange(false);
    }

    public OrderManagerAdapter(Context context, List<T> objects) {
        super(context, 0);
        this.objects = objects;
        mLock = new Object();
    }

    @Override
    public void add(T object) {
        synchronized (mLock) {
            objects.add(object);
        }
    }

    @Override
    public void addAll(Collection<? extends T> collection) {
        synchronized (mLock) {
            objects.addAll(collection);
        }
    }

    @Override
    public void insert(T object, int index) {
        synchronized (mLock) {
            objects.add(index, object);
        }
    }

    @Override
    public void remove(T object) {
        synchronized (mLock) {
            objects.remove(object);
        }
    }

    @Override
    public void clear() {
        synchronized (mLock) {
            objects.clear();
        }
    }

    @Override
    public int getCount() {
        return objects.size();
    }

    @Override
    public T getItem(int position) {
        return objects.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public int getPosition(T item) {
        return objects.indexOf(item);
    }

    public List<T> getObjects() {
        return objects;
    }
}

And this is my EditText code inside the fragment:

EditText inputSearch = (EditText) rootView.findViewById(R.id.inputSearch);
        inputSearch.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {

            }

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {

            }

            @Override
            public void afterTextChanged(Editable s) {
                Log.d(Constants.TAG, "*** Search value changed: " + s.toString());
                adapter.getFilter().filter(s);
            }
        });

The search seems to be working for a first time filtering, in the sense that i type some filter string, the list gets updated, but then when i clear the text i can't see the original list being displayed, i get an empty list.

Upvotes: 0

Views: 503

Answers (2)

Ifrit
Ifrit

Reputation: 6821

  1. OrderManagerAdapter should not be extending ArrayAdapter. You're overriding enough methods it makes ArrayAdapter largely irrelevant. In addition, you are not overriding all the mutate methods, which means you can get yourself into some really nasty trouble if you invoke one of them.

  2. None of OrderManagerAdapter mutate methods are invoking notifyDataSetChange. The adapter won't update properly without them.

  3. Infact, why even override ArrayAdapter when it appears you want all the functionality it provides? Your OrderManagerAdapter is not done correctly at all and will only contribute to more problems. You'd be better off scrapping OrderManagerAdapter and having ArticolAdapter extend ArrayAdapter.

  4. Your filter is totally incorrect:

    a) That executes on a background thread and you have zero sync blocks around all the list modifications.

    b) It completely changes the List reference for the adapter, which means OrderManagerAdapter will not be pointing to the same List of data that ArticolAdapter is and all future attempts to modifying the adapter will fail.

    c) It also invalidates the data after every filter...which basically means your adapters dead and shouldn't report any more data changes

I'm not sure what your end goal is, but if all you need is an easy way to customize the filtered results for an ArrayAdapter, just use this guy. It'll save you a whole bunch of headaches.

Upvotes: 1

kpatel
kpatel

Reputation: 21

It seems you doesnt refresh your listview with adapter.notifyDataSetChanged(); after reassigning the data to adapter. First update your dapter and than call adapter.notifyDataSetChanged(); in your activity

Upvotes: 0

Related Questions