转载: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. 12232 - Exclusive-OR

    12232 - Exclusive-OR 题目大意是可以设定一个点Xp=v,或者Xp^Xq=v,然后查询Xa^Xb^Xc...等于多少. 由于异或操作跟判连通性很类似,这里可以使用并查集来解决,对于X ...

  2. P66、面试题8:旋转数组的最小数字

    题目:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转.输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数 ...

  3. dom解析器机制 web基本概念 tomcat

    0 作业[cn.itcast.xml.sax.Demo2]   1)在SAX解析器中,一定要知道每方法何时执行,及SAX解析器会传入的参数含义 1 理解dom解析器机制 1)dom解析和dom4j原理 ...

  4. Android 签名(8)签名前用Zipalign简单优化

    1 为什么要优化 Android SDK中包含一个“zipalign”的工具,它能够对打包的应用程序进行优化.在你的应用程序上运行zipalign,使得在运行时Android与应用程序间的交互更加有效 ...

  5. 摄像头(2)调用系统拍照activity来录像

    import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager ...

  6. WinAPI——Windows 消息

    消息 值  注释  WM_NULL $0000   WM_CREATE $0001   WM_DESTROY $0002   WM_MOVE $0003   WM_SIZE $0005   WM_AC ...

  7. bzoj1044

    好题 第一问不难,毕竟二分答案类的题目在USACO上都练了好多遍了 第二问充分的暴露了我dp渣的本性 一开始楞是没想出来 f[i,j]表示到第i根木棒切了j刀满足最长段小于等于ans的方案数 式子是这 ...

  8. BZOJ2140: 稳定婚姻

    题解: 题意就是求二分图的必须边. 我们有结论: 在残量网络上跑tarjan,对于一条边(u,v) 如果该边满流||scc[u]==scc[v],那么该边是可行边. 因为如果scc[u]==scc[v ...

  9. POJ 2135 Farm Tour(最小费用最大流,变形)

    题意:给一个无向图,FJ要从1号点出发到达n号点,再返回到1号点,但是路一旦走过了就会销毁(即回去不能经过),每条路长度不同,那么完成这趟旅行要走多长的路?(注:会有重边,点号无序,无向图!) 思路: ...

  10. session问题

    如果 <sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42424&q ...