转载: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. SPRING IN ACTION 第4版笔记-第九章Securing web applications-001-SpringSecurity简介(DelegatingFilterProxy、AbstractSecurityWebApplicationInitializer、WebSecurityConfigurerAdapter、@EnableWebSecurity、@EnableWebMvcS)

    一.SpringSecurity的模块 At the least, you’ll want to include the Core and Configuration modules in your ...

  2. 好用的linux命令

    sudo chown -R `whoami` /usr/local # ps aux |grep php-fpm php-frm start and stop php-fpm -D killall p ...

  3. Python之模块篇

    简介 你已经学习了如何在你的程序中定义一次函数而重用代码.如果你想要在其他程序中重用很多函数,那么你该如何编写程序呢?你可能已经猜到了,答案是使用模块.模块基本上就是一个包含了所有你定义的函数和变量的 ...

  4. CSS+DIV布局初练—DIV元素必须成对出现?

    一直做C/S开发的工作,但是很少做和布局相关的工作,往往都是同事将界面设计好,自己填写代码而已,对于B/S的工作,做过,但是很少没有像C/S这么多,界面布局的话,更无从谈起. 日子就这么过,一天一个样 ...

  5. “WIZnet杯”以太网技术竞赛即将开始!

  6. MySQL高效分页解决方案集

    一,最常见MYSQL最基本的分页方式: select * from content order by id desc limit 0, 10 在中小数据量的情况下,这样的SQL足够用了,唯一需要注意的 ...

  7. Windows 7/8 自带定时关机命令

    快捷键“Windows + R”,输入cmd打开cmd.exe程序,输入以下对应命令.   两种定时关机方式: 定时任务法 输入命令“at hh:mm shutdown -s”,Enter——添加了一 ...

  8. Hibernate中的query.setFirstResult(),query.setMaxResults();

    一.query.scroll()和query.setFirstResult(),query.setMaxResults();这两种方法都可以取到一定范围内的数据,用来数据分页显示.那么两者区别,以及两 ...

  9. poj3692

    首先这道题很容易想到二分图相关(给的很明确了): 但是我们发现,男孩之间都互相认识,女孩之间也互相认识 这样是不能划分点集的 但是男孩之间都互相认识,女孩之间也互相认识,所以男孩和男孩,女孩和女孩之间 ...

  10. 3月下旬剩余poj题解

    poj1700 数学推导+简单dp poj2390 水题不说什么了 poj3260 先对找的钱做完全背包,在对能付的钱做多重背包,注意这道题能付的钱数的上界 poj2516 裸的最小费用最大流了没什么 ...