过滤自定义适配器返回不正确的结果

时间:2012-12-22 11:25:26

标签: android filter android-listview baseadapter

检查:

screenshot

我正在尝试在ListView上实施过滤器。但我面临一个非常奇怪的问题。如果我在T中输入字母EditText,则ListView的名称将从BJ开始填充。请帮忙。

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 个答案:

答案 0 :(得分:3)

您的问题来自于您设置getView()方法的方式以及如何在SparseBooleanArray中设置选中的项目。我已经编辑了适配器的代码,它现在应该可以工作了。主要更改位于OnCheckedChangeListener字段:

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();
        }
    }
}

答案 1 :(得分:1)

getView()方法中,您没有更新UI以获得过滤结果的值。 所以它返回了旧结果的视图。

在返回paramView之前,将视图的数据更新为过滤结果中的数据,并将其从viewHolder的准备中删除,因为这只被调用了几次。


编辑: 这是我对代码的更正。我认为它会解决它:

@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;
}

编辑: 这是我如何处理过滤的示例:

@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;
  }

答案 2 :(得分:1)

我还在我的应用程序中实现了过滤器列表视图。为此,我只需要一段代码。检查它,如果它有帮助。

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);

            }
        });