继承BaseAdapter实现Filterable的adapter类完整示例

转载: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,第二个是绑定的对象。在需要的地方,我可以这么使用:

[java] view plaincopy

  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("过滤关键字");

时间: 2024-08-10 21:21:11

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

Android技术18:Android中Adapter类详解

1.Adapter设计模式 Android中adapter接口有很多种实现,例如,ArrayAdapter,BaseAdapter,CursorAdapter,SimpleAdapter,SimpleCursorAdapter等,他们分别对应不同的数据源.例如,ArrayAdater对应List和数组数据源,而CursorAdapter对应Cursor对象(一般从数据库中获取的记录集).这些Adapter都需要getView方法返回当前列表项显示的View对象.当Model发生改变时,会调用Ba

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

大三学生一个,喜欢编程,喜欢谷歌,喜欢Android,所以选择的方向自然是Android应用开发,开博第一篇,希望以后会有更多的进步. 最近在做一个记账App的时候,需要一个Activity来显示每个月的消费各个项目的比例,Activity中主要用到一个ListView,ListView中包括一个TextView来显示类型的名称,一个TextView来显示所占比例,一个ProgressBar来显示进度条,让每个条目的比例更加清晰.如下图(这里只提供实现方法,界面效果暂不提供) 因为这种效果比较特

继承BaseAdapter覆写getView()方法解析

当我们继承BaseAdapter自定义适合自己使用的Adapter时候,不可避免的要覆写getView()方法.自己在分析蓝牙4.0官方源代码遇到这个问题,分析了几遍,有所领悟,参考了这篇博文http://blog.csdn.net/pkxiuluo01/article/details/7380974,现结合蓝牙4.0官方的这部分代码将getView()解析一下. //当界面每显示出来一个item时,就会调用该方法,getView()有三个参数,第一个参数表示该item在Adapter中的位置:

Adapter类下的Gallery实例详解

通常我们更多的继承BaseAdapter来编写自己的Adapter类,因为BaseAdapter类是其他Adapter类的基类.在世界的运用过程中呢,我们一般需要重写这类的一些方法: getCount() ;获取当前Adapter的Items数目 getItem(int position);获取相应Position(位置)的Item getItemId(int position);获取相应position的Item在LIst中的row id getView(int positon,View co

类继承,定义了一个点类point,然后线条类line继承了point类,正方形类square继承line类

类继承,定义了一个点类point,然后线条类line继承了point类,正方形类Suare继承line类 正方形四个角坐标关系如图 1 /** 2 * 3 java继承实例. 4 5 6 定义了一个点类point,然后线条类line继承了point类,正方形类square继承line类. 7 8 */ 9 10 //点类 11 class PointDemo 12 { 13 private int x; 14 private int y; 15 private static int pCount

C# 根据对象类完整名称,创建对象实例

转自:http://blog.csdn.net/mm33211/article/details/8143890 C# 根据对象类完整名称,创建对象实例 /// <summary> /// 根据指定的类全名,返回对象实例 /// </summary> /// <param name="objFullName">对象完整名称(包名和类名),如:com.xxx.Test</param> public object createObjectIns

从Qt谈到C++(二):继承时的含参基类与初始化列表

提出疑问 当我们新建一个Qt的图形界面的工程时,我们可以看看它自动生成的框架代码,比如我们的主窗口名称为MainWindow,我们来看看mainwindow.cpp文件: MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { } 不同于一般的继承,这里的父类的括号里带有参数,我们通常都使用过不带参数,甚至不带括号的基类名称.这里的基类为什么带着参数呢? C++继承与构造函数

JAVA设计模式-装饰设计模式-继承体系的由来和装饰类的优化

首先看一下我们设计类的过程: 专门用于读取数据的类 MyReader l--MyTextReader:根据不同的功能会不断延伸很多子类 l--MyMeidaReader l--MyDataReader l--.......... 为了提高以上子类的工作效率,需要加入缓冲区技术.所以又会出现下面的类的继承体系. (体系1) MyReader l--MyTextReader:根据不同的功能会不断延伸很多子类 l--MyBufferedTextReader l--MyMeidaReader l--My

是否存在不继承自System.Object类型的类

分析问题 可能读者的固有思维认为.NET中所有的类型都必须继承自System.Object,这样的认识过于绝对,且不完全正确.在.NET中,.NET设计小组为中间语言的编译器ILasm.exe添加了noautoinherit开关,当这个开关被打开时,编译器将不会默认年地把类型认为继承自System.Object. 首先介绍一下中间语言的编译工具:ILasm.exe.这是.NET Framework提供的一个编译工具,它的作用是把中间语言(MSIL)编译成可执行的PE文件.该工具非常有用,它不仅使