ListView ArrayAdapter filtering - duplicate items
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
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
精彩评论