Reputation: 2903
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
Reputation: 6821
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.
None of OrderManagerAdapter mutate methods are invoking notifyDataSetChange. The adapter won't update properly without them.
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.
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
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