转载: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. log4cxx在linux下的编译和使用

    [下载] [编译动态库] [使用动态库]

  2. live555源码研究(五)------DynamicRTSPServer类

    一.类DynamicRTSPServer作用 1,提供RTSP服务 二.类DynamicRTSPServer继承关系图

  3. QListWidget代码刷新界面

    我有一个特殊效果要求实现(其实很弱智,也变成特殊效果,汗一下自己):两个QRadioButton切换的时候,让旁边的QListWidget自动变化不同的背景色.想了很多办法: 1. 控件自己刷新,不行 ...

  4. ENVI Services Engine5.1 应用开发入门教程

    原文地址: ENVI Services Engine5.1 应用开发入门教程_ENVI-IDL中国_新浪博客 http://blog.sina.com.cn/s/blog_764b1e9d0102uy ...

  5. linux目录/术语/英文

    1./bin :获得最小的系统可操作性所需要的命令2./boot :内核和加载内核所需的文件3./dev :终端.磁盘.调制解调器等的设备项4./etc :关键的启动文件和配置文件5./home :用 ...

  6. sc.exe管理系统服务

    sc.exe管理系统服务 下面介绍SC,SC QC,and SC QUERY sc.exe create HomerSatelliteDesktopGC binPath= "D:XXXXXX ...

  7. 你想建设一个能承受500万PV/每天的网站吗?

    (如果感觉有帮助,请帮忙点推荐,添加关注,谢谢!你的支持是我不断更新文章的动力.本博客会逐步推出一系列的关于大型网站架构.分布式应用.设计模式.架构模式等方面的系列文章) 你想建设一个能承受500万P ...

  8. 微信5.4 AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8" ?> - <manifest android:versionCode ...

  9. Git教程(2)官方命令文档及常用命令表

    http://www.cnblogs.com/angeldevil/archive/2013/11/26/3238470.html 1,官方命令文档 http://www.git-scm.com/do ...

  10. C#.Net 如何动态加载与卸载程序集(.dll或者.exe)1----C#中动态加载和卸载DLL

    我们知道在C++中加载和卸载DLL是一件很容易的事,LoadLibrary和FreeLibrary让你能够轻易的在程序中加载DLL,然后在任何地方卸载. 在C#中我们也能使用Assembly.Load ...