转载: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. ArcGIS学习记录—dbf shp shx sbn sbx mdb adf等类型的文件的解释

    原文地址: ArcGIS问题:dbf shp shx sbn sbx mdb adf等类型的文件的解释 - Silent Dawn的日志 - 网易博客 http://gisman.blog.163.c ...

  2. paip.提升用户体验----gcc c++ JIT-debugging 技术

    paip.提升用户体验----gcc  c++ JIT-debugging 技术 作者Attilax ,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http ...

  3. python学习笔记六--用户自定义类

    一.类: 1. 面向对象. 2. 定义了新的对象类型. 定义了两个属性:name,pay 定义了两个方法:lastName,giveRaise

  4. C语言中指针数组和数组指针的区别

    指针数组:首先它是一个数组,数组的元素都是指针,数组占多少个字节由数组本身决定.它是“储存指针的数组”的简称. 数组指针:首先它是一个指针,它指向一个数组.在32 位系统下永远是占4 个字节,至于它指 ...

  5. Hive简介

    实验简介 我们本节课程主要介绍 Hive 的相关知识,将会涉及以下内容: Hive 的定义 Hive 的体系结构 Hive 与关系数据库的区别 Hive 的应用场景 Hive 的存储 一.什么是 Hi ...

  6. 学Android开发 这19个开发工具助你顺风顺水

    学Android开发 这19个开发工具助你顺风顺水 要想快速开发一个Android应用,通常会用到很多工具,巧妙利用这些工具,能让我们的开发工作事半功倍,节省大量时间,下面大连Android开发培训小 ...

  7. Mysql slave 状态之Seconds_Behind_Master

    在MySQL的主从环境中,我们可以通过在slave上执行show slave status来查看slave的一些状态信息,其中有一个比较重要的参数Seconds_Behind_Master.那么你是否 ...

  8. 【转】使用NDK生成native C/C++的可执行程序

    原文网址:http://www.linuxidc.com/Linux/2011-08/40901.htm 众所周知, NDK可以生成lib,让java程序通过jni来调用,其实,NDK也可以生成C/C ...

  9. C#.NET开源项目、机器学习、商务智能

    所以原谅我,不能把所有的都发上来,太杂了,反而不好. 1..NET时间周期处理组件 这个组件很小,主要是对时间日期,特别是处理时间间隔以及时间范围非常方便.虽然.NET自带了时间日期的部分功能,但可能 ...

  10. 使用ServiceStackRedis链接Redis简介

    注:关于如何在windows,linux下配置redis,详见这篇文章:) 目前网上有一些链接Redis的C#客户端工具,这里介绍其中也是目前我们企业版产品中所使用的ServiceStackRedis ...