【问题标题】:What is the easiest filter method for custom listview adapter?自定义列表视图适配器最简单的过滤方法是什么?
【发布时间】:2012-08-03 20:08:13
【问题描述】:

我有一个 EditText 和 Custom ListView Adapter 连接 sqllite db。 我可以添加、删除和编辑记录。下一个目标是通过 EditText 过滤记录。 我写了这段代码,但它没有正确过滤。

private EditText et_search_filter;
private TextWatcher watcher_search_filter;
et_search_filter = (EditText) findViewById(id.et_search_box);
et_search_filter.addTextChangedListener(watcher_search_filter);

watcher_search_filter = new TextWatcher() {
public void onTextChanged(CharSequence s, int start, int before, int count) {
    adapter.getFilter().filter(s);              
}

public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}

public void afterTextChanged(Editable s) {
}

};

这里是我的游标方法:

public ArrayList<Item> item_get_all() {
    ArrayList<Item> itemList = new ArrayList<Item>();

    String selectQuery = "SELECT * FROM " + TABLE_ITEMS;

    SQLiteDatabase db = this.getWritableDatabase();

    Cursor cursor = db.rawQuery(selectQuery, null);

    if (cursor.moveToFirst()) {
        do {
            Item dbitems = new Item();
            dbitems.setID(Integer.parseInt(cursor.getString(cursor.getColumnIndex(items_id))));
            dbitems.setName(cursor.getString(cursor.getColumnIndex(items_item_name)));
            dbitems.setBrand(cursor.getString(cursor.getColumnIndex(items_brand)));
            dbitems.setItemType(cursor.getString(cursor.getColumnIndex(items_type)));
            dbitems.setModel(cursor.getString(cursor.getColumnIndex(items_model)));
            dbitems.setNote(cursor.getString(cursor.getColumnIndex(items_note)));
            dbitems.setPurchaseFrom(cursor.getString(cursor.getColumnIndex(items_purchase_from)));
            dbitems.setPurchasePrice(cursor.getString(cursor.getColumnIndex(items_price)));
            dbitems.setPurchaseDate(cursor.getLong(cursor.getColumnIndex(items_purchase_date)));
            itemList.add(dbitems);              
        } while (cursor.moveToNext());
    }
    db.close();
    return itemList;
}

我这样调用光标适配器:

public void getItemList() {     
    ArrayList<Item> itemArray = new ArrayList<Item>();      
    itemArray = db.item_get_all();      
    adapter = new ItemAdapter(this, R.layout.items_row, itemArray);
    ilistViewItems.setAdapter(adapter);                     
}

这是我的 ItemAdapter.java 和 Item_row.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >
    <TextView
        android:id="@+id/tv_item_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:text="@string/nullstr"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:textColor="#ffffff"
        android:textSize="13dp"
        android:textStyle="bold" />
    <TextView
        android:id="@+id/tv_item_brand"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/tv_item_name"
        android:text="@string/nullstr"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="#bbbbbb"
        android:textSize="11dp" />
    <TextView
        android:id="@+id/tv_purchase_date"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/tv_item_name"
        android:text="@string/nullstr"
        android:textAppearance="?android:attr/textAppearanceSmall"
        android:textColor="#aabbbb"
        android:textSize="11dp" />
</RelativeLayout>

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import db.Item;
public class ItemAdapter extends ArrayAdapter<Item>{
private ArrayList<Item> items;
private TextView item_name;    
private TextView item_brand;
private TextView item_purchase_date;      

public ItemAdapter(Context context, int textViewResourceId, ArrayList<Item> objects) {
    super(context, textViewResourceId, objects);
    this.items = objects;

}

public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        LayoutInflater vi = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = vi.inflate(R.layout.items_row, null);
    }

    item_name = (TextView) convertView.findViewById(R.id.tv_item_name);    

    item_brand = (TextView) convertView.findViewById(R.id.tv_item_brand);
    item_purchase_date = (TextView) convertView.findViewById(R.id.tv_purchase_date);       

    item_name.setText(items.get(position).getName());       
    item_brand.setText("[" + items.get(position).getItemType() + "] " + items.get(position).getBrand() + " " + items.get(position).getModel());
    item_purchase_date.setText(items.get(position).getPurchasedDateStr());

    return convertView;
}   

}

【问题讨论】:

  • 您使用的是什么类型的适配器?您发布的内容适用于 ArrayAdapter,但不适用于 CursorAdapter。
  • 好像是 CursorAdapter。数据来自 sqldb 游标。
  • 好的,发布你用来获取光标的函数,我将引导你完成它。 (当我有一个真实的例子时会更容易。)
  • 亲爱的@Sam,我发布了我的功能和代码。谢谢
  • 太好了,你会发布 ItemAdapter 和 items_row.xml 吗?

标签: android sqlite filter textview adapter


【解决方案1】:

重写

你实现了 Item 的 toString() 方法吗?

public class Item {
    ...

    // Define a method to return a String that describes each Item, preferably unique String
    public String toString() {
        return name + "  " + brand + "  " + model + "  " + type;
    }
}

当我对您发布的所有内容都使用此方法时,EditText 会很好地过滤 ListView。让我知道这个简单的更改是否适合您。

效率

我想指出一些技巧,让您现有的代码运行得更快。

查看您的数据库适配器的 get_item_all() 方法。

  • 对于一个新的Cursor,你只需要调用moveToNext(),当有有效数据要读取时,这将返回true。
  • SQliteDatabases 中的 ID 是 long 数据类型。您应该将 Item 中的 id 从 int 更改为 long 并使用 Cursor.getLong()。
  • 您搜索每个列的索引以查找每个 项。一次查找索引并将它们存储在本地。

总而言之,这样效率更高:

int idIndex = cursor.getColumnIndex(items_id);
int nameIndex = cursor.getColumnIndex(items_item_name);
//etc.

while (cursor.moveToNext()) {
    Item dbitems = new Item();

    dbitems.setID(cursor.getLong(idIndex));
    dbitems.setName(cursor.getString(nameIndex));
    ...
    itemList.add(dbitems);              
}

接下来,看看 Item.getView()。

  • 您只需要创建一个 LayoutInflater 并将其存储在类中。我建议在你的构造函数中初始化它。
  • 每次调用 getView() 时,您都会多次使用 findViewById() 和 item.get(position)。每当用户滚动 ListView 时,适配器使用 getView() 来显示每一行,您只需在 convertView 为空时调用 findViewById()。

大家一起:

创建一个名为 LayoutInflater mInflater 的变量并在构造函数中对其进行初始化:

mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

在你的 ItemAdapter 添加这个嵌套类:

public class ViewHolder {
    TextView name;
    TextView brand;
    TextView purchase_date;
}

在 getView() 中:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder viewHolder;
    Item item = (Item) getItem(position);
    if(convertView == null) {
        convertView = mInflater.inflate(R.layout.list_item, parent, false);

        viewHolder = new ViewHolder();
        viewHolder.name = (TextView) convertView.findViewById(R.id.tv_item_name);
        viewHolder.brand = (TextView) convertView.findViewById(R.id.tv_item_brand);
        viewHolder.purchase_date = (TextView) convertView.findViewById(R.id.tv_purchase_date);
        convertView.setTag(viewHolder);
    }
    else
        viewHolder = (ViewHolder) convertView.getTag();

    viewHolder.name.setText(item.getName());
    viewHolder.brand.setText("[" + item.getItemType() + "] " + item.getBrand() + " " + item.getModel());
    viewHolder.purchase_date.setText(item.getPurchasedDateStr());
    return convertView;
}

如果已经创建了 convertView,您是否看到工作量减少了多少?希望对您有所帮助。

【讨论】:

  • 非常感谢@Sam。它现在正在工作。我对我的代码做了很多修改。我将代码更改为 getView 方法。我现在就改。
【解决方案2】:

我没有阅读所有内容,但他说明了过滤方法。所以我会推荐autoCompleteTextView,因为它会在达到一种可用的文本类型时完成。当你按下一个字母让我们说“S”时,它会显示三星或索尼 acd

网页示例:

public class CountriesActivity extends Activity {
     protected void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         setContentView(R.layout.countries);

         ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                 android.R.layout.simple_dropdown_item_1line, COUNTRIES);
         AutoCompleteTextView textView = (AutoCompleteTextView)
                 findViewById(R.id.countries_list);
         textView.setAdapter(adapter);
     }

     private static final String[] COUNTRIES = new String[] {
         "Belgium", "France", "Italy", "Germany", "Spain"
     };
 }

【讨论】:

  • 好吧,我的回答仍然有效。您可以使用自动完成文本视图,下面将是一个显示相关信息的列表视图。这个过程会有点复杂,因为您必须创建一个与 autocompletetextview 关联的新类来锁定名称下拉列表,然后填充列表视图。
  • 我会尝试autocompletetextview 谢谢@Akyl。但我的问题是不同的。当我按“s”键时,所有记录都消失了。有事发生。但我不明白发生了什么背景。但有一个事实。过滤方法不成功。
【解决方案3】:

您的ItemAdapter 似乎扩展了ArrayAdapter,因此您应该创建自定义过滤器。检查此SO questionanother similar。在第一个链接中,还有另一个选项是 override toString 在您的 Item 类中返回您要过滤的字段。自己检查。如果您想过滤光标适配器,请遵循 Sam 指南(在您发布的代码中,您从光标获取数据并放入您的类,因此它不是光标适配器)。使用FilterQueryProvider 注册您的适配器或在runQueryOnBackgroundThread 中返回filtered cursor

【讨论】:

  • 为什么要创建自定义过滤器?此代码适用于数组适配器,但不适用于光标适配器。
  • 您的ItemAdapter 扩展ArrayAdapter。我没有看到任何cursor adapter
  • 但我正在使用 Cursor 获取记录集。它是一个光标适配器。对不起@Yul,我不知道游标和数组适配器有什么区别。
  • 我会试试你的建议,什么是最好的? FilterQueryProvider 还是 runQueryOnBackgroundThread??
  • 您只需拉出一个光标并从中获取数据到您的Item 类。 Cursor Adapteradapter that exposes data from a Cursor to a ListView widget 。关于FilterQueryProviderrunQueryOnBackgroundThread 是一样的。我经常使用runQueryOnBackgroundThread。如果你想把你的适配器改成Cursor Adapter,这里有一些example1example2
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-06
  • 2011-12-31
相关资源
最近更新 更多