转载:http://www.lai18.com/content/1631130.html

目标:自定义ListView项布局通常需要自己实现Adapter,并通过搜索关键字筛选部分数据。且关键字变长变短,甚至为空时都应该正确搜索。

关键字:ListView Adapter ViewHolder Filter

最终实现如下效果:

借鉴了几篇资料后终于弄好了一个带过滤器的数据adapter。网上要一次性弄全资料还挺困难的,主要借鉴:
http://www.cnblogs.com/mengdd/p/3254323.html (Adapter中ViewHolder的使用)
http://www.oschina.net/code/snippet_1021353_35874 (Adapter实现Filterable。有问题)
http://stackoverflow.com/questions/25458519/how-to-implement-filterable-on-a-baseadapter(Adapter实现Filterable。正解) 
要点:

1、继承BaseAdapter,getView()方法要使用ViewHolder方式减少实例化view

2、实现Filterable接口,要注意保留原始数据(上述两篇实现Filterable文章的区别)

3、synchronized 同步,效果实现,先不深究了

上代码:其中VoStation是我自定义的实体类。

public class VoStationAdapter extends BaseAdapter implements Filterable {

    // 适配器的当前数据
private ArrayList<VoStation> _data;
// 适配器的原始数据
private List<VoStation> _originalData;
// 自定义的过滤器
private SearchFilter _filter; private LayoutInflater _inflater;
private final Object _lock = new Object();// 同步锁?不太懂 /**
* 构造函数
*
* @param context
* 上下文
* @param data
* 适配器数据
*/
public VoStationAdapter(Context context, ArrayList<VoStation> data) {
_inflater = LayoutInflater.from(context);
_data = data;
} /**
* 【见备注1】重设原始数据 在原始数据发生变化时使用
**/
public void resetData(ArrayList<VoStation> data) {
_data = data;
if (_originalData != null)
_originalData = _data;
} /** 获得数据过滤器 */
public Filter getFilter() {
if (_filter == null) {
_filter = new SearchFilter();
}
return _filter;
} @Override
public int getCount() {
return _data.size();
} @Override
public VoStation getItem(int position) {
return _data.get(position);
} @Override
public long getItemId(int position) {
// <span style="font-family: Arial, Helvetica, sans-serif;">【见备注2】</span><span style="font-family: Arial, Helvetica, sans-serif;">自定义ID</span>
// 在此最好返回数据的唯一标识,在一些特定情况下使用到
// 如果没有,此处一般返回position
return _data.get(position).getID();
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder = null; if (convertView == null) {
holder = new ViewHolder(); convertView = _inflater.inflate(R.layout.listitem_bill, parent,
false);// 注意参数 holder.title = (TextView) convertView.findViewById(R.id.tvTitle);
holder.text = (TextView) convertView.findViewById(R.id.tvText);
holder.time = (TextView) convertView.findViewById(R.id.tvDate);
holder.image = (ImageView) convertView.findViewById(R.id.ivIcon);
// convertView.setTag(holder);//【见备注3】我还需要绑定数据,若不绑定,使用本行代替下行
convertView.setTag(R.id.tag1, holder);
} else {
holder = (ViewHolder) convertView.getTag(R.id.tag1);
}
holder.title.setText(_data.get(position).getName());
holder.text.setText("基站很长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长长");
holder.time.setText(String.format("%s,%s",
_data.get(position).getLon(), _data.get(position).getLat()));
holder.image.setImageResource(R.drawable.item);
convertView.setTag(R.id.tagVO, _data.get(position));// 【见备注3】绑定数据 return convertView;
} class ViewHolder {
ImageView image;
TextView title;
TextView text;
TextView time;
} // 内部类:数据过滤器
class SearchFilter extends Filter { @Override
protected FilterResults performFiltering(CharSequence constraint) {
// 定义过滤规则
FilterResults filterResults = new FilterResults(); // 保存原始数据
if (_originalData == null) {
synchronized (_lock) {
_originalData = new ArrayList<VoStation>(_data);
}
} // 如果搜索框内容为空,就恢复原始数据
if (TextUtils.isEmpty(constraint)) {
synchronized (_lock) {
filterResults.values = _originalData;
filterResults.count = _originalData.size();
}
} else { // 否则过滤出新数据
String filterString = constraint.toString().trim()
.toLowerCase(Locale.US);// 过滤首尾空白,小写过滤
ArrayList<VoStation> newValues = new ArrayList<VoStation>(); for (VoStation vo : _originalData) {
if (vo.getName().toLowerCase(Locale.US)
.contains(filterString)) {
newValues.add(vo);
}
filterResults.values = newValues;
filterResults.count = newValues.size();
}
}
return filterResults;
} @SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint,
FilterResults results) {
_data = (ArrayList<VoStation>) results.values;// 更新适配器的数据
if (results.count > 0) {
notifyDataSetChanged();// 通知数据发生了改变
} else {
notifyDataSetInvalidated();// 通知数据失效
}
} }
}

备注1:adapter的过滤器,实现对原始数据的筛选,筛选出的新数据一般只是起到临时显示的作用,不能替换掉原始数据。但我们有时候会对原始数据做更新后再次筛选,比如增删。resetData()重要在于重置了私有变量_originalData,这样才能使“新的原始数据”可以被正确得筛选。

备注2:关于 adapter的getItemId()方法,见我另外一篇文章:

baseadapter.getItemId的使用方法:实现listview筛选、动态删除

备注3:此处仅为新手解释一下,大神肯定都知道什么意思。如果只绑定一个数据,使用convertView.setTag(holder)即可。但我想试试为每个列表项的view绑定对应的实体类对象,所以,此处我需要绑定两个数据,一个是holder,一个是实体类对象vo。因此使用convertView.setTag(int,object)方法,第一个参数是用资源文件定义的一个ID,第二个是绑定的对象。在需要的地方,我可以这么使用:

  1. String s1 = "ViewTagVo:"  + ((VoStation) view.getTag(R.id.tagVO)).getName();

定义好adapter后,在需要过滤数据时的调用:

ArrayList<VoStation> data = new ArrayList<VoStation>();
data.add(vo);//添加数据...
VoStationAdapter adapter = new VoStationAdapter(this, data);
lvContent.setAdapter(adapter);//lvContent是ListView组件
adapter.getFilter().filter("过滤关键字");

继承BaseAdapter实现Filterable的adapter类完整示例的更多相关文章

  1. Andriod基础——Adapter类

    Android是完全遵循MVC模式设计的框架,Activity是Controller,layout是View,因为layout五花八门,很多数据都不能直接绑定上去,所以Android引入了Adapte ...

  2. Android开发学习之路-自定义ListView(继承BaseAdapter)

    大三学生一个,喜欢编程,喜欢谷歌,喜欢Android,所以选择的方向自然是Android应用开发,开博第一篇,希望以后会有更多的进步. 最近在做一个记账App的时候,需要一个Activity来显示每个 ...

  3. Android继承BaseAdapter时要重写的函数的说明

    原文来自:http://www.2cto.com/kf/201405/299601.html,我自己做了一些修改 Android中继承BaseAdapter后需要重写四个函数,但一般还要写一个构造函数 ...

  4. 实现如下类之间的继承关系,并编写Music类来测试这些类。

    实现如下类之间的继承关系,并编写Music类来测试这些类. package com.hanqi.test; public class Instrument { //输出弹奏乐器 public void ...

  5. Android中Adapter类的使用 “Adapter”

    Adapter用来把数据绑定到扩展了AdapterView类的视图组(例如:ListView或Gallery).Adapter负责创建代表所绑定父视图中的底层数据的子视图. 可以创建自己的Adapte ...

  6. 继承 派生 super()经典类 新式类

    '''1什么是继承? 继承一种新建类的方式,在python中支持一个儿子继承多个爹 新建的类称为子类的或者派生类 父类有可以称为基类或者超类 子类会‘遗传’父类的属性 2 为什么要用继承 减少代码冗余 ...

  7. Adapter类 调用Activity中的函数

    在Adapter类中可以定义一个MainActivity变量,在初始化时,对其赋值,例如fragment的适配器中: private MainActivity context; private Lis ...

  8. C++继承具体解释之二——派生类成员函数具体解释(函数隐藏、构造函数与兼容覆盖规则)

    在这一篇文章開始之前.我先解决一个问题. 在上一篇C++继承详解之中的一个--初探继承中,我提到了在派生类中能够定义一个与基类成员函数同名的函数,这样派生类中的函数就会覆盖掉基类的成员函数. 在谭浩强 ...

  9. C++ //多继承语法 C++中允许一个类继承多个类

    1 //多继承语法 C++中允许一个类继承多个类 2 #include <iostream> 3 #include <string> 4 using namespace std ...

随机推荐

  1. semantic versioning语义化版本号

    语义化版本号 是由github创始人 Tom Preston-Werner 发起的一个关于软件版本号的命名规范,关于这个规范详细的说明可以在 官网 查看,也可访问其 GitHub项目页面 ,官网文档: ...

  2. Webform——Repeater多表联合显示

    对于一个表里,通过外键连接如何显示另一个表的数据,前Winform里可以用封装类来实现. 对于Webform,可以用封装类,也可以用Repeater的ItemDataBound事件(//在项被绑定数据 ...

  3. bzoj1937

    这道题没弄明白 初始模型很好想,是用到了最小生成树的性质 加入非树边后树上形成的环,非树边一定大于等于任意树边 然后考虑树边一定是缩小,非树边一定是增大 有di+wi>=dj-wj wi+wj& ...

  4. Arch 常用工具

    一.网络浏览 pacman -S firefox firefox-i18n注:该命令中的前者为 Firefox 主程序,后者为语言包.pacman -S opera 二.图像编辑 pacman -S ...

  5. Warning: Name is nonexistent or not a directory

    Every time I start up MATLAB, I receive this message: Warning: Name is nonexistent or not a director ...

  6. Sharepoint中用treeview来显示组织机构的人员状态的webpart

    转:http://www.cnblogs.com/virusswb/archive/2009/04/28/1445517.html

  7. web前端优化-温故知新系列(1)

    有关web前端优化的博文,博客园中有许多网友的博客中都有介绍,而且详细.精准.楼主打算写这个博客,算是对自己一年工作来的一个总结和积累有些知识从别的地方拷贝过来的,但是都审查过. 引言: 1. 慢的页 ...

  8. uboot环境变量与内核MTD分区关系

    uboot 与系统内核中MTD分区的关系: 分区只是内核的概念,就是说A-B地址放内核,C-D地址放文件系统,(也就是规定哪个地址区间放内核或者文件系统)等等. 1:在内核MTD中可以定义分区A~B, ...

  9. 非均匀B样条拟合MATLAB程序

    直接上代码,多的不再说了. %------------------非均匀B样条拟合MATLAB程序----------------- clear k=; x=load('data.txt'); [n, ...

  10. redis-3.0.0集群的安装及使用

    redis集群需要至少6个节点(偶数节点),3个主节点,3个从节点.注意:集群模式最好不要keys *查询数据. 1 下载redis,官网下载3.0.0版本,之前2.几的版本不支持集群模式.下载地址: ...