Filtering custom adapter returning incorrect resul

2019-03-05 09:04发布

Check:

screenshot

I am trying to implement filter on my ListView. But I am facing a very strange kind of problem. If I type letter T in the EditText the ListView is getting filled with names starting from B , J. Please help.

public class MyCustomAdapter extends BaseAdapter implements Filterable {

Context mContext;
private LayoutInflater mInflater;
SparseBooleanArray mSparseBooleanArray;
private ArrayList<Map<String,String>> mAdapData = new ArrayList<Map<String, String>>();
private ArrayList<Map<String,String>> mOriginalData = new ArrayList<Map<String, String>>();

public MyCustomAdapter(Context mContext) {
    mInflater = (LayoutInflater) mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    mSparseBooleanArray = new SparseBooleanArray();
}

public ArrayList<String> getCheckedItems() {
    ArrayList<String> mTempArry = new ArrayList<String>();
    for (int i = 0; i < mAdapData.size(); i++) {
        if (mSparseBooleanArray.get(i)) {
            Map<String, String> map = (Map<String, String>) mAdapData.get(i);
            final String numbr = map.get("Phone").toString();
            mTempArry.add(numbr);
        }
    }
    return mTempArry;
}

@Override
public int getCount() {
    return this.mAdapData.size();
}

public void addItem(String paramString1, String paramString2) {
    Map<String, String> NameNumber = new HashMap<String, String>();
    NameNumber.put("Name", paramString1);
    NameNumber.put("Phone", paramString2);
    this.mAdapData.add(NameNumber);
    this.mOriginalData.add(NameNumber);
    notifyDataSetChanged();
}

@SuppressWarnings("unchecked")
public Object getItem(int paramInt) {
    return (ArrayList<Map<String, String>>) this.mAdapData.get(paramInt);
}

@Override
public long getItemId(int paramInt) {
    return paramInt;
}

@Override
public View getView(final int paramInt, View paramView, ViewGroup paramViewGroup) {

    ViewHolder viewHolder;

    if (paramView == null) {
        viewHolder = new ViewHolder();
        paramView = mInflater.inflate(R.layout.multiplecontactview, null);
        viewHolder.tvName = (TextView) paramView.findViewById(R.id.txtContactName);
        viewHolder.tvNumber = (TextView) paramView.findViewById(R.id.txtContactNumber);
        viewHolder.cb = (CheckBox) paramView.findViewById(R.id.checkBox1);
        viewHolder.cb.setTag(paramInt);
        viewHolder.cb.setChecked(mSparseBooleanArray.get(paramInt));
        viewHolder.cb.setOnCheckedChangeListener(mCheckedChangeListener);
        viewHolder.tvName.setTextColor(Color.BLACK);
        viewHolder.tvNumber.setTextColor(Color.BLACK);
        for (int i = 0; i < mAdapData.size(); i++) {
            Map<String, String> map = (Map<String, String>) mAdapData.get(paramInt);
            final String name = map.get("Name").toString();
            Log.e("Name", name);
            final String numbr = map.get("Phone").toString();
            Log.e("Number", numbr);
            viewHolder.tvName.setText(name);
            viewHolder.tvNumber.setText(numbr);
        }
        paramView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder) paramView.getTag();
    }       
    return paramView;
}

OnCheckedChangeListener mCheckedChangeListener = new OnCheckedChangeListener() {
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        mSparseBooleanArray.put((Integer) buttonView.getTag(), isChecked);
    }
};

public static class ViewHolder {
    TextView tvName;
    TextView tvNumber;
    CheckBox cb;
}

@Override
public Filter getFilter() {
    return new MyContactFilter();
}

@SuppressLint("DefaultLocale")
private class MyContactFilter extends Filter {

    @Override
    protected FilterResults performFiltering(CharSequence constraint) {
        FilterResults results = new FilterResults();
        ArrayList<Map<String, String>> mFilteredData = new ArrayList<Map<String, String>>();

        if (!TextUtils.isEmpty(constraint)) { 
            for(int i = 0; i < mAdapData.size(); i++) {
                Map<String, String> map = (Map<String, String>) mAdapData.get(i);
                final String names = map.get("Name").toString();
                final String numbr = map.get("Phone").toString();
                if(names.toLowerCase().contains(constraint.toString().toLowerCase())) {
                    Map<String, String> FilNameNumber = new HashMap<String, String>();
                    FilNameNumber.put("Name", names);
                    FilNameNumber.put("Phone", numbr);
                    mFilteredData.add(FilNameNumber);
                }
            }
            results.values = mFilteredData;
            results.count = mFilteredData.size();

        } else {
            synchronized (mOriginalData) {
                results.values = mOriginalData;
                results.count = mOriginalData.size();
            }
        }
        return results;
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void publishResults(CharSequence cs, FilterResults fr) {
        mAdapData = (ArrayList<Map<String, String>>) fr.values;
        notifyDataSetChanged();
    }
}
}

3条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-03-05 09:06

I have also implemented filter List View in my application. For that, I just need a snippet of code. Check it, if it helps.

editText.addTextChangedListener(new TextWatcher() {

            public void onTextChanged(CharSequence arg0, int arg1, int arg2,
                    int arg3) {

            }
            public void beforeTextChanged(CharSequence arg0, int arg1,
                    int arg2, int arg3) {

            }
            public void afterTextChanged(Editable arg0) {
                sendToList.this.adapter.getFilter().filter(arg0);

            }
        });
查看更多
Bombasti
3楼-- · 2019-03-05 09:09

Your problems come from the way you setup the getView() method and how you set the checked item in that SparseBooleanArray. I've edited your adapter's code and it should work now. The main changes are in the OnCheckedChangeListener field:

public class MyCustomAdapter extends BaseAdapter implements Filterable {

    private Context mContext;
    private LayoutInflater mInflater;
    private SparseBooleanArray mSparseBooleanArray;
    // from where do you get the data?
    private ArrayList<Map<String, String>> mAdapData = new ArrayList<Map<String, String>>();
    private ArrayList<Map<String, String>> mOriginalData = new ArrayList<Map<String, String>>();

    public MyCustomAdapter(Context mContext) {
        mInflater = (LayoutInflater) mContext
                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mSparseBooleanArray = new SparseBooleanArray();
    }

    public ArrayList<String> getCheckedItems() {
        ArrayList<String> mTempArry = new ArrayList<String>();
        for (int i = 0; i < mAdapData.size(); i++) {
            if (mSparseBooleanArray.get(i)) {
                Map<String, String> map = (Map<String, String>) mAdapData
                        .get(i);
                final String numbr = map.get("Phone");
                mTempArry.add(numbr);
            }
        }
        return mTempArry;
    }

    @Override
    public int getCount() {
        return this.mAdapData.size();
    }

    public void addItem(String paramString1, String paramString2) {
        Map<String, String> NameNumber = new HashMap<String, String>();
        NameNumber.put("Name", paramString1);
        NameNumber.put("Phone", paramString2);
        mAdapData.add(NameNumber);
        mOriginalData.add(NameNumber);
        notifyDataSetChanged();
    }

    @SuppressWarnings("unchecked")
    public Object getItem(int paramInt) {
        return (ArrayList<Map<String, String>>) this.mAdapData.get(paramInt);
    }

    @Override
    public long getItemId(int paramInt) {
        return paramInt;
    }

    @Override
    public View getView(final int paramInt, View paramView,
            ViewGroup paramViewGroup) {
        ViewHolder viewHolder;
        if (paramView == null) {
            viewHolder = new ViewHolder();
            paramView = mInflater.inflate(R.layout.adapters_specialfilterrow,
                    paramViewGroup, false);
            viewHolder.tvName = (TextView) paramView
                    .findViewById(R.id.textView1);
            viewHolder.tvNumber = (TextView) paramView
                    .findViewById(R.id.textView2);
            viewHolder.cb = (CheckBox) paramView.findViewById(R.id.checkBox1);
            paramView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) paramView.getTag();
        }
        viewHolder.cb.setTag(paramInt);
        viewHolder.cb.setOnCheckedChangeListener(null);
        viewHolder.cb.setChecked(mSparseBooleanArray.get(paramInt));
        viewHolder.cb.setOnCheckedChangeListener(mCheckedChangeListener);
        viewHolder.tvName.setTextColor(Color.BLACK);
        viewHolder.tvNumber.setTextColor(Color.BLACK);
        Map<String, String> map = (Map<String, String>) mAdapData.get(paramInt);
        final String name = map.get("Name");
        final String numbr = map.get("Phone");
        viewHolder.tvName.setText(name);
        viewHolder.tvNumber.setText(numbr);
        return paramView;
    }

    OnCheckedChangeListener mCheckedChangeListener = new OnCheckedChangeListener() {
        public void onCheckedChanged(CompoundButton buttonView,
                boolean isChecked) {
            // get the item from the current mAdapData
            Map<String, String> item = mAdapData.get((Integer) buttonView
                    .getTag());
            int position = -1;
            // see where is the item placed in the mOriginalData and use that
            // position
            for (int i = 0; i < mOriginalData.size(); i++) {
                final Map<String, String> tmp = mOriginalData.get(i);
                if (tmp.get("Name").toLowerCase().equals(item.get("Name").toLowerCase())) {
                    position = i;
                    break;
                }
            }
            mSparseBooleanArray.put(position, isChecked);
        }
    };

    public static class ViewHolder {
        TextView tvName;
        TextView tvNumber;
        CheckBox cb;
    }

    @Override
    public Filter getFilter() {
        return new MyContactFilter();
    }

    @SuppressLint("DefaultLocale")
    private class MyContactFilter extends Filter {

        @Override
        protected FilterResults performFiltering(CharSequence constraint) {
            FilterResults results = new FilterResults();
            ArrayList<Map<String, String>> mFilteredData = new ArrayList<Map<String, String>>();

            if (!TextUtils.isEmpty(constraint)) {
                for (int i = 0; i < mAdapData.size(); i++) {
                    Map<String, String> map = (Map<String, String>) mAdapData
                            .get(i);
                    final String names = map.get("Name");
                    final String numbr = map.get("Phone");
                    if (names.toLowerCase().contains(
                            constraint.toString().toLowerCase())) {
                        Map<String, String> FilNameNumber = new HashMap<String, String>();
                        FilNameNumber.put("Name", names);
                        FilNameNumber.put("Phone", numbr);
                        mFilteredData.add(FilNameNumber);
                    }
                }
                results.values = mFilteredData;
                results.count = mFilteredData.size();
            } else {
                synchronized (mOriginalData) {
                    results.values = mOriginalData;
                    results.count = mOriginalData.size();
                }
            }
            return results;
        }

        @SuppressWarnings("unchecked")
        @Override
        protected void publishResults(CharSequence cs, FilterResults fr) {
            mAdapData = (ArrayList<Map<String, String>>) fr.values;
            notifyDataSetChanged();
        }
    }
}
查看更多
Bombasti
4楼-- · 2019-03-05 09:26

in the getView() method , you didn't update the UI to have the values of the filtered results . so it returned views with old results .

just before return paramView , update the view's data to what you have in the filtered results , and remove it from the preparation of the viewHolder , since this is called only a few times .


EDIT: here's my correction of the code . i think it will fix it:

@Override
public View getView(final int paramInt, View paramView, ViewGroup paramViewGroup) {

ViewHolder viewHolder;

if (paramView == null) {
    viewHolder = new ViewHolder();
    paramView = mInflater.inflate(R.layout.multiplecontactview, null);
    viewHolder.tvName = (TextView) paramView.findViewById(R.id.txtContactName);
    viewHolder.tvNumber = (TextView) paramView.findViewById(R.id.txtContactNumber);
    viewHolder.cb = (CheckBox) paramView.findViewById(R.id.checkBox1);
    viewHolder.tvName.setTextColor(Color.BLACK);
    viewHolder.tvNumber.setTextColor(Color.BLACK);
    paramView.setTag(viewHolder);
    viewHolder.cb.setOnCheckedChangeListener(mCheckedChangeListener);
} else {
    viewHolder = (ViewHolder) paramView.getTag();
}       
viewHolder.cb.setTag(paramInt);
viewHolder.cb.setChecked(mSparseBooleanArray.get(paramInt));


Map<String, String> map = (Map<String, String>) mAdapData.get(paramInt);
final String name = map.get("Name").toString();
Log.e("Name", name);
final String numbr = map.get("Phone").toString();
Log.e("Number", numbr);
viewHolder.tvName.setText(name);
viewHolder.tvNumber.setText(numbr);

return paramView;
}

EDIT: here's a sample of how i handled the filtering :

@Override
public Filter getFilter()
  {
  final Filter filter=new Filter()
    {
      @Override
      protected FilterResults performFiltering(final CharSequence constraint)
        {
        _lastFilterConstraint=constraint;
        if(TextUtils.isEmpty(constraint))
          return null;
        final String constraintToCheck=constraint.toString().toLowerCase(Locale.getDefault());
        final FilterResults results=new FilterResults();
        // <- here i do the filtering itself and later put the results into "results"
        results.values=values;
        results.count=values.size();
        return results;
        }

      @SuppressWarnings("unchecked")
      @Override
      protected void publishResults(final CharSequence constraint,final FilterResults results)
        {
        _filteredItems==null ? null : (ArrayList<Item>)results.values;
        notifyDataSetChanged();
        }
    };
  return filter;
  }

@Override
public int getCount()
  {
  if(_filteredItems!=null)
    return _filteredItems.size();
  return _originalItems.size();
  }

@Override
public Item getItem(final int position)
  {
  if(_filteredItems!=null)
    {
    if(position<_filteredItems.size())
      return _filteredItems.get(position);
    return null;
    }
  if(position<_originalItems.size())
    return _originalItems.get(position);
  return null;
  }

@Override
public View getView(final int position,final View convertView,final ViewGroup parent)
  {
  final View inflatedView;
  final ViewHolder viewHolder;
  if(convertView==null)
    {
    //<- here i inflate the view into the inflatedView
    }
  else
    {
    inflaterView=convertView;
    viewHolder=(ViewHolder)inflaterView.getTag();
    }
  // <- here i use getItem and update the view according to its data .
  return inflaterView;
  }
查看更多
登录 后发表回答