JavaNullPointer
JavaNullPointer

Reputation: 1211

Custom filtering for Custom ArrayAdapter in ListView

i write a own ArrayAdapter like this one:

public class PoiListAdapter extends ArrayAdapter<Poi> implements Filterable {

    private Context context;
    private final List<Poi> valuesPoi;
    private ItemsFilter mFilter;

    public PoiListAdapter(Context context, List<Poi> valuesPoi) {
        super(context, R.layout.poilist);
        this.context = context;
        this.valuesPoi = valuesPoi;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater) context
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        View rowView = inflater.inflate(R.layout.poilist, parent, false);
        TextView textViewName = (TextView) rowView.findViewById(R.id.name_poi);
        TextView textViewDis = (TextView) rowView
                .findViewById(R.id.discrip_poi);
        textViewName.setText(valuesPoi.get(position).getName());
        textViewDis.setText(valuesPoi.get(position).getDiscription());
        return rowView;
    }

    /**
     * Implementing the Filterable interface.
     */
    public Filter getFilter() {
        if (mFilter == null) {
            mFilter = new ItemsFilter(this);
        }
        return mFilter;
    }

    public List<Poi> getValuesPoi() {
        return valuesPoi;
    }

    public void addValuesPoi(Poi p) {
        valuesPoi.add(p);
    }
      @Override
  public void clear() {
    valuesPoi.clear();
  }
}

For this Adapter I want to implement a search function. Therefore I implement a custom Filter-Class:

public class ItemsFilter extends Filter {

private PoiListAdapter poiListAdapter;

public ItemsFilter(PoiListAdapter poiListAdapter) {
    this.poiListAdapter = poiListAdapter;
}

@Override
protected FilterResults performFiltering(CharSequence constraint) {
    constraint = constraint.toString().toLowerCase();
    FilterResults result = new FilterResults();
    ArrayList<Poi> filterList = new ArrayList<Poi>();
    if (constraint != null && constraint.toString().length() > 0) {
        ArrayList<Poi> orginalList = new ArrayList<Poi>(
                poiListAdapter.getValuesPoi());

        for (Poi p : orginalList) {
            if (p.getName().toLowerCase().contains(constraint))
                filterList.add(p);
        }
        Log.i("DEBUG", orginalList.toString());
        result.values = filterList;
        result.count = filterList.size();

    } else {

        result.values = poiListAdapter.getValuesPoi();
        result.count = poiListAdapter.getValuesPoi().size();

    }
    return result;
}

@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
    ArrayList<Poi> fitems = (ArrayList<Poi>) results.values;
    poiListAdapter.clear();
    for (Poi p : fitems) {
        poiListAdapter.addValuesPoi(p);
        poiListAdapter.notifyDataSetChanged();
    }
}

The 1. Problem

....is that i got a java.util.concurrentmodificationexception for:

for (Poi p : fitems) {
            poiListAdapter.addValuesPoi(p);
            poiListAdapter.notifyDataSetChanged();
        }

I think the problem is that I want to modifi a Arraylist under access. I think I have to work with synchronized, but I have never worked with it before.

UPDATE: This is problem is solved! Here the Code:

for(Iterator<Poi> i = fitems.iterator(); i.hasNext();) {
        Poi p = i.next();
        poiListAdapter.addValuesPoi(p);
        //poiListAdapter.notifyDataSetChanged();
    }

The 2. Problem

The List view is empty at start. At the start i want to shown all elements! Also is nothing displayed by searching an element! Listview shows nothing at the moment!

Upvotes: 1

Views: 4170

Answers (4)

Dhunju_likes_to_Learn
Dhunju_likes_to_Learn

Reputation: 1366

@JavaNullPointer : I was having the same problem as you did. I tried to implement the solutions provided here but was having different kinds of problem.. after thinking for a while, I assumed that the default Filter might be using toString() method of the object to filter... this turned to me right. It saved me a lot of hassle..

reading at your codes, I believe you want to filter by the name field of Poi class. if so, then the quick solution would be SOLUTION:

public class Poi{

//your constructors and methods

@Override
public String toString(){
   return getName(); 
}

Upvotes: 1

JavaNullPointer
JavaNullPointer

Reputation: 1211

i could solve my Problems. Here my solution!

    package hsos.ds.helper;

import hsos.ds.db.Poi;

import java.util.ArrayList;
import java.util.List;
import android.widget.Filter;

public class ItemsFilter extends Filter {

    private PoiListAdapter poiAdapter;
    private List<Poi> valuesPoi;
    private List<Poi> filteredPoi;

    public ItemsFilter(PoiListAdapter _poiAdapter) {
        this.poiAdapter = _poiAdapter;
        this.valuesPoi = poiAdapter.getValuesPoi();
        this.filteredPoi = poiAdapter.getFilteredPoi();
    }

    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        FilterResults result = new FilterResults();
        constraint = constraint.toString().toLowerCase();

        if (constraint == null || constraint.length() == 0) {
            ArrayList<Poi> list = new ArrayList<Poi>(valuesPoi);
            result.values = valuesPoi;
            result.count = valuesPoi.size();

        } else {
            final ArrayList<Poi> orginalList = new ArrayList<Poi>(valuesPoi);
            final ArrayList<Poi> filterList = new ArrayList<Poi>();
            int count = orginalList.size();
            for (int i = 0; i < count; i++) {
                final Poi p = orginalList.get(i);
                if (p.getName().toLowerCase().contains(constraint))
                    filterList.add(p);
            }
            result.values = filterList;
            result.count = filterList.size();
        }
        return result;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence constraint, FilterResults results) {
        filteredPoi = (List<Poi>) results.values;
        poiAdapter.notifyDataSetChanged();
        poiAdapter.clear();
        int count = filteredPoi.size();
        for (int i = 0; i < count; i++) {
            poiAdapter.add(filteredPoi.get(i));
            poiAdapter.notifyDataSetInvalidated();
        }
    }
}

and the Adapter:

public class PoiListAdapter extends ArrayAdapter implements Filterable {

private List<Poi> valuesPoi;
private List<Poi> filteredPoi;
private ItemsFilter mFilter;

public PoiListAdapter(Context context, List<Poi> valuesPoi) {
    super(context, R.layout.poilist);
    this.valuesPoi = new ArrayList<Poi>(valuesPoi);
    this.filteredPoi = new ArrayList<Poi>(valuesPoi);
    this.mFilter = new ItemsFilter(this);
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View v = convertView;
    if (v == null) {
        LayoutInflater vi = (LayoutInflater) getContext().getSystemService(
                Context.LAYOUT_INFLATER_SERVICE);
        v = vi.inflate(R.layout.poilist, null);
    }

    Poi p = filteredPoi.get(position);

    if (p != null) {
        TextView tt = (TextView) v.findViewById(R.id.name_poi);
        TextView bt = (TextView) v.findViewById(R.id.discrip_poi);
        if (tt != null) {
            tt.setText(p.getName());
        }
        if (bt != null) {
            bt.setText(p.getDiscription());
        }
    }
    return v;
}

@Override
public Filter getFilter() {
    if (mFilter == null) {
        mFilter = new ItemsFilter(this);
    }
    return mFilter;
}

public List<Poi> getValuesPoi() {
    return valuesPoi;
}


public List<Poi> getFilteredPoi() {
    return filteredPoi;

}

}

To show the complete list onStart() i insert the a little "hack" in the onStart()-Method of my activity because the complete list is shown after an input:

if(searchText!=null){
        searchText.setText(" ");
        searchText.setText("");
    }

Upvotes: 0

Blackbelt
Blackbelt

Reputation: 157437

The for-each loop use an Iterator internally, and you can not add nothing to your collection while you are iterating (that's why of the exception). Try creating a new instance of the ArrayList and interate upon it

@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
    ArrayList<Poi> fitems = new ArrayList((ArrayList<Poi>) results.values);
    poiListAdapter.clear();
    for (Poi p : fitems) {
        poiListAdapter.addValuesPoi(p);
        poiListAdapter.notifyDataSetChanged();
    }
}

the for-each is something like:

for(Iterator<Poi> i = fitms.iterator(); i.hasNext(); ) {
  Poi item = i.next();    
}

Problem 2:

The List is empty at start probably because the dataset you submit is empty

Upvotes: 1

Manishika
Manishika

Reputation: 5564

ConcurentModification can be avoided in two ways :

  1. poiListAdapter.addValuesPoi(p) add this code in a synchronized method .Synchronized method can't be accessed concurrently .

  2. Use Collections.synchronizedList

Upvotes: 2

Related Questions