2012-12-22 130 views
0

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

screenshot

我想实现我的ListView过滤器。但是我面临着一个很奇怪的问题。如果我在EditText中键入字母T,则ListView正在填写从B,J开始的名称。请帮忙。

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

你的问题都来自你的方式设置的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(); 
     } 
    } 
} 
+0

非常感谢你 –

+0

认真,我已经发布了相同的答案,并得到选择...... :( –

+0

@androiddeveloper你的答案只是解决方案的一部分(这是我包括在我的答案(我承认,在),但OnCheckedChangeListener监听器的变化也很重要,并最终解决了用户的所有问题。 – Luksprog

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; 
    } 
+0

但为什么当我搜索字母T时,listview正在填充包含字母B的名称? –

+0

@ user1822826因为你只在'convertView'为'null'(最初)时设置了'TextViews'。过滤很可能会显示以前的行没有设置新数据的“TextViews”。在你完成过滤之后,你应该看看'mAdapData'包含了什么。 – Luksprog

+0

@Luksprog请告诉我如何解决这个错误。 –

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

      } 
     }); 
+0

这将适用于我的适配器?我正在使用'ArrayList >来填充'listview' –

+0

不确定,但你可以试试。我用它作为单个对象。 –

相关问题