问题
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
回答1:
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
来源:https://stackoverflow.com/questions/7753829/listview-arrayadapter-filtering-duplicate-items