Question

I trying to filter listview with custom adapter. When I start typing on edittext the list view should be filtered. Below is the code of adapter. The custom object has overridden method toString which return the name of the facebook user. I didn't override ArrayAdapter methods getItem,add or remove.

public class FacebookFriendsAdapter extends ArrayAdapter<FacebookUser> {
    private Activity activity;
    public ImageLoader imageLoader;
    private HashMap<String, Integer> alphaIndexer;
    private String[] sections = new String[0];
    private boolean enableSections;

    public FacebookFriendsAdapter(Context context, int textViewResourceId,ArrayList<FacebookUser> newItems) {
        super(context, textViewResourceId, newItems);
        imageLoader = new ImageLoader(context.getApplicationContext());
    }

    public static class ViewHolder {
        public TextView text;
        public ImageView image;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View rowView = convertView;
        FacebookUser fcbu = getItem(position);

        if (convertView == null) {
            LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            rowView = vi.inflate(R.layout.facebook_friendslist_row, null);
            final ViewHolder holder = new ViewHolder();
            holder.text = (TextView) rowView.findViewById(R.id.facebook_rowFriendName);
            holder.image = (ImageView) rowView.findViewById(R.id.facebookRowUserFoto);
            rowView.setTag(holder);
        } else {
            rowView = convertView;
        }
        ViewHolder holder = (ViewHolder) rowView.getTag();

        String imageurl = "http://graph.facebook.com/" + fcbu.getId()+ "/picture";
        holder.text.setText(fcbu.getName());
        holder.image.setTag(imageurl);
        imageLoader.DisplayImage(imageurl, holder.image);
        return rowView;
    }
}

On the activity which hold EditText I created a TextWatcher like:

private TextWatcher filterTextWatcher = new TextWatcher() {

        public void afterTextChanged(Editable s) {

        }

        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
        }

        public void onTextChanged(CharSequence s, int start, int before,
                int count) {
            facebookAdapter.getFilter().filter(s);
        }
    };

Everything works fine expect that after the list is filtered the filtered items are duplicated.

A would appreciate any idea what may cause this. Thanks

Was it helpful?

Solution

I solved the problem thanks to How to write a custom filter for ListView with ArrayAdapter.

Below is the adapted custom Adapter

public class FBAdapter extends ArrayAdapter<FacebookUser> {
    public ImageLoader imageLoader;
    private ArrayList<FacebookUser> items;
    private ArrayList<FacebookUser> originalItems = new ArrayList<FacebookUser>();
    private FBAdapterFilter filter;
    private final Object mLock = new Object();

    public FBAdapter(Context context, int textViewResourceId,
            ArrayList<FacebookUser> newItems) {
        super(context, textViewResourceId, newItems);
        imageLoader = new ImageLoader(context);
        items = newItems;
        cloneItems(newItems);
    }

    protected void cloneItems(ArrayList<FacebookUser> items) {
        for (Iterator iterator = items.iterator(); iterator.hasNext();) {
            FacebookUser gi = (FacebookUser) iterator.next();
            originalItems.add(gi);
        }
    }

    @Override
    public int getCount() {
        synchronized (mLock) {
            return items != null ? items.size() : 0;
        }
    }

    @Override
    public FacebookUser getItem(int item) {
        FacebookUser gi = null;
        synchronized (mLock) {
            gi = items != null ? items.get(item) : null;

        }
        return gi;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View rowView = convertView;
        final FacebookUser fcbu = getItem(position);

        if (convertView == null) {
            LayoutInflater vi = (LayoutInflater) getContext().getSystemService(
                    Context.LAYOUT_INFLATER_SERVICE);
            rowView = vi.inflate(R.layout.facebook_friendslist_row, null);
            final ViewHolder holder = new ViewHolder();
            holder.text = (TextView) rowView
                    .findViewById(R.id.facebook_rowFriendName);
            holder.image = (ImageView) rowView
                    .findViewById(R.id.facebookRowUserFoto);
            holder.checkbox = (CheckBox) rowView
                    .findViewById(R.id.chkInviteFacebookFriend);
            holder.checkbox
                    .setOnCheckedChangeListener(new OnCheckedChangeListener() {
                        @Override
                        public void onCheckedChanged(CompoundButton buttonView,
                                boolean isChecked) {
                            FacebookUser element = (FacebookUser) holder.checkbox
                                    .getTag();
                            element.setSelected(buttonView.isChecked());
                            holder.checkbox.setTag(element);
                        }
                    });
            rowView.setTag(holder);
            holder.checkbox.setTag(fcbu);

        } else {
            rowView = convertView;
            ((ViewHolder) rowView.getTag()).checkbox.setTag(fcbu);

        }
        ViewHolder holder = (ViewHolder) rowView.getTag();

        String imageurl = "http://graph.facebook.com/" + fcbu.getId()
                + "/picture";
        holder.text.setText(fcbu.getName());
        holder.image.setTag(imageurl);
        holder.checkbox.setChecked(fcbu.isSelected());

        imageLoader.DisplayImage(imageurl, holder.image);
        return rowView;
    }

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

    /**
     * Custom Filter implementation for the items adapter.
     * 
     */
    private class FBAdapterFilter extends Filter {
        protected FilterResults performFiltering(CharSequence prefix) {
            // Initiate our results object
            FilterResults results = new FilterResults();

            // No prefix is sent to filter by so we're going to send back the
            // original array
            if (prefix == null || prefix.length() == 0) {
                synchronized (mLock) {
                    results.values = originalItems;
                    results.count = originalItems.size();
                }
            } else {
                synchronized (mLock) {
                    // Compare lower case strings
                    String prefixString = prefix.toString().toLowerCase();
                    final ArrayList<FacebookUser> filteredItems = new ArrayList<FacebookUser>();
                    // Local to here so we're not changing actual array
                    final ArrayList<FacebookUser> localItems = new ArrayList<FacebookUser>();
                    localItems.addAll(originalItems);
                    final int count = localItems.size();

                    for (int i = 0; i < count; i++) {
                        final FacebookUser item = localItems.get(i);
                        final String itemName = item.getName().toString()
                                .toLowerCase();

                        // First match against the whole, non-splitted value
                        if (itemName.startsWith(prefixString)) {
                            filteredItems.add(item);
                        } else {
                        } /*
                         * This is option and taken from the source of
                         * ArrayAdapter final String[] words =
                         * itemName.split(" "); final int wordCount =
                         * words.length;
                         * 
                         * for (int k = 0; k < wordCount; k++) { if
                         * (words[k].startsWith(prefixString)) {
                         * newItems.add(item); break; } } }
                         */
                    }

                    // Set and return
                    results.values = filteredItems;
                    results.count = filteredItems.size();
                }// end synchronized
            }

            return results;
        }

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence prefix, FilterResults results) {
            // noinspection unchecked
            synchronized (mLock) {
                final ArrayList<FacebookUser> localItems = (ArrayList<FacebookUser>) results.values;
                notifyDataSetChanged();
                clear();
                // Add the items back in
                for (Iterator iterator = localItems.iterator(); iterator
                        .hasNext();) {
                    FacebookUser gi = (FacebookUser) iterator.next();
                    add(gi);
                }
            }// end synchronized
        }
    }

    public ArrayList<FacebookUser> getSelectedItems() {
        ArrayList<FacebookUser> result = new ArrayList<FacebookUser>();
        for (FacebookUser friend : items) {
            if (friend.isSelected())
                result.add(friend);
        }
        return result;
    }
}

I also loaded facebook friends on AsyncTask so I changed that way so adapter is populated in postExecute:

@Override
        protected void onPostExecute(ArrayList<FacebookUser> result) {

            if (result != null && result.size() > 0) {
                facebookAdapter = new FBAdapter(
                        InviteFriendsFromFacebookActivity.this,
                        R.layout.facebook_friendslist_row, result);
                facebookListView.setAdapter(facebookAdapter);
                facebookListView.setVisibility(View.VISIBLE);
                facebookAdapter.notifyDataSetChanged();
            }

        }

Now the issue is gone. Thanks

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top