如何使用CursorAdapter实现自动完成功能

4
我有一个SQLite数据库,其中包含2张表格,每个表格都有4000行以上,用于自动完成。我看到了一些非常简单的例子,它们使用字符串数组提供自动完成,或者使用联系人列表来完成相同的操作。显然,这些方法在我的情况下都无法使用。如何使用自己的SQLite数据库和自己的自动完成数据进行自动完成呢?我需要创建内容提供者吗?如何创建?请给我一些示例,因为我找不到任何相关的内容。我已经成功地覆盖了SQLiteOpenHelper,将数据库从资产文件夹复制到Android设备上的/data/data/MY_PACKAGE/databases/文件夹中。我创建了一个自定义的CursorAdapter,它使用我的自定义SQLiteOpenHelper并从runQueryOnBackgroundThread返回一个游标对象。但是,我会出现一些奇怪的错误,例如缺少某个_id列。我已经向我的表格中添加了_id列,但我还不理解Filterable接口的作用以及我的数据在何时被筛选。我需要重写哪些方法/类呢?谢谢。
1个回答

7

它可以工作。

您需要来自这里的SQLiteOpenHelper。您基本上需要将您的数据库从assets文件夹复制到特定文件夹中。然后,您需要一个使用您自定义的SQLiteOpenHelper的自定义CursorAdapter。

这是我的活动的onCreate方法。


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.search);

        KeywordsCursorAdapter kwadapter = new KeywordsCursorAdapter(this, null);

        txtKeyword = (AutoCompleteTextView)this.findViewById(R.id.txtKeyword);
        txtKeyword.setAdapter(kwadapter);
        txtCity = (AutoCompleteTextView)this.findViewById(R.id.txtCity);
        btnSearch = (Button)this.findViewById(R.id.btnSearch);
        btnSearch.setOnClickListener(this);
    }

这是一个游标适配器。在构造时,当传入null时,表示不使用游标。


public class KeywordsCursorAdapter extends CursorAdapter {

    private Context context;

    public KeywordsCursorAdapter(Context context, Cursor c) {
        super(context, c);
        this.context = context;
    }

    //I store the autocomplete text view in a layout xml.
    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        View v = inflater.inflate(R.layout.keyword_autocomplete, null);
        return v;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        String keyword = cursor.getString(cursor.getColumnIndex("keyword"));
        TextView tv = (TextView)view.findViewById(R.id.txtAutocomplete);
        tv.setText(keyword);
    }

    //you need to override this to return the string value when
    //selecting an item from the autocomplete suggestions
    //just do cursor.getstring(whatevercolumn);
    @Override
    public CharSequence convertToString(Cursor cursor) {
        //return super.convertToString(cursor);
        String value = "";
        switch (type) {
        case Keywords:
            value = cursor.getString(DatabaseHelper.KEYWORD_COLUMN);
            break;
        case Cities:
            value = cursor.getString(DatabaseHelper.CITY_COLUMN);
            break;
        }
        return value;
    }

    @Override
    public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
        //return super.runQueryOnBackgroundThread(constraint);
        String filter = "";
        if (constraint == null) filter = "";
        else
            filter = constraint.toString();
                //I have 2 DB-s and the one I use depends on user preference
        SharedPreferences prefs  = PreferenceManager.getDefaultSharedPreferences(context);
        //String selectedCountryCode = prefs.getString("selectedCountry", "GB");
        String selectedCountryCode = prefs.getString(context.getString(R.string.settings_selected_country), "GB");
        selectedCountryCode += "";

                //Here i have a static SQLiteOpenHelper instance that returns a cursor.
        Cursor cursor = MyApplication.getDbHelpers().get(selectedCountryCode.toLowerCase()).getKeywordsCursor(filter);
        return cursor;
    }
}

这里是返回光标的部分:它只是一个带有类似条件的选择器。

public class DatabaseHelper extends SQLiteOpenHelper {

...

    public synchronized Cursor getKeywordsCursor (String prefix) {
        if (database == null) database = this.getReadableDatabase();
        String[] columns = {"_id", "keyword"};
        String[] args = {prefix};

        Cursor cursor;
        cursor = database.query("keywords", columns, "keyword like '' || ? || '%'", args, null, null, "keyword", "40");

        int idcol = cursor.getColumnIndexOrThrow("_id");
        int kwcol = cursor.getColumnIndexOrThrow("keyword");

        while(cursor.moveToNext()) {
            int id = cursor.getInt(idcol);
            String kw = cursor.getString(kwcol);
            Log.i("keyword", kw);
        }

        cursor.moveToPosition(-1);
        return cursor;
    }

...

}

您也可以创建自定义内容提供程序,但在这种情况下,它只是另一个无用的类,您需要覆盖它。


那个选择条件是什么意思? - adrian
选择 _id, keyword FROM 关键词 WHERE 关键词 LIKE '' || ? || '%'。? 代表参数, || 表示连接符。我不确定如何将参数转换为字符串,因此我使用空字符串进行连接。正确应该是 ? || '%' - gyozo kudor
我有一个类似的问题,但我就是无法解决它:|... cursor = database.query("keywords", columns, "keyword like '' || ? || '%'", args, null, null, "keyword", "40");.....现在,第一个"keywords"是表的名称吗?而且我还不明白你所说的"keyword like '' || ? || '%'"是什么意思...."keyword like"是不能替换的信息吗?"?"是参数...我还是不明白。如果您能进一步解释一下,我将不胜感激。 - adrian
还有一件事..... public Cursor runQueryOnBackgroundThread(CharSequence constraint) 返回一个新的游标,但它不会筛选自动完成的条目...你必须设置一个过滤器,而你在代码中没做任何处理:) - adrian
老实说,我不知道数据是如何被过滤的。 - gyozo kudor
1
这里有一个 SQL 语法的例子:http://www.1keydata.com/sql/sqllike.html。`?` 只是一个参数,在运行时会被 SQLite 替换为有效的字符串。我认为每按下一个字符,就会执行 runQueryOnBackgroundThread 并返回一个新的游标。是的,我可能应该重用游标,但我很高兴终于让它工作了,我没有进行优化。 - gyozo kudor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接