IllegalArgumentException:无效列 - SEARCHVIEW

IllegalArgumentException: Invalid column - SEARCHVIEW

我想在使用 SearchView 时从我的数据库 table 获得建议。

我得到 IllegalArgumentException:无效的列(列的名称)

    private static final HashMap<String, String> mColumnMap = buildColumnMap();

    //Build a map for all columns that may be requested, which will be given to SQLiteQueryBuilder.
    //This allow ContentProvider to request columns without the need to know real column names and
    //create the alias itself
    private static HashMap<String, String> buildColumnMap() {
        HashMap<String, String> map = new HashMap<String, String>();

        map.put(SearchManager.SUGGEST_COLUMN_TEXT_1, "rowid AS " +
                CookingContract.FoodEntry.COLUMN_NAME);
        map.put(SearchManager.SUGGEST_COLUMN_TEXT_2, "rowid AS " +
                CookingContract.FoodEntry.COLUMN_DESCRIPTION);
        map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, "rowid AS " + CookingContract.FoodEntry._ID);


        return map;
    }


    //Return a Cursor over all words that match the given query
    public Cursor getWordMatches(String query, String[] columns) {
        String selection = CookingContract.FoodEntry.COLUMN_NAME + " LIKE ?";
        String[] selectionArgs = new String[]{"%" + query + "%"};

        return query(selection, selectionArgs, columns);
    }

    //The SQLiteBuilder provides a map for all possible columns requested to actual columns in the
    //DB, creating a simple column alias mechanism by which the ContentProvider doesn't need to know
    //the real column names
    private Cursor query(String selection, String[] selectionArgs, String[] columns) {
        SQLiteQueryBuilder builder = new SQLiteQueryBuilder();
        builder.setTables(CookingContract.FoodEntry.TABLE_NAME);
        builder.setProjectionMap(mColumnMap);


        Cursor cursor = builder.query(getReadableDatabase(),
                columns, selection, selectionArgs, null, null, null);

        if (cursor == null) {
            return null;
        } else if (!cursor.moveToFirst()) {
            cursor.close();
            return null;
        }
        return cursor;
    }
}

这是我的 ContentProvider 的部分代码

public Cursor query(Uri uri, String[] projection, String selection,
                    String[] selectionArgs, String sortOrder) {
    Cursor retCursor;
    switch (sUriMatcher.match(uri)) {

        case SEARCH_SUGGEST:

            if (selectionArgs == null) {
                throw new IllegalArgumentException(
                        "selectionArgs must be provided for the Uri: +"uri");
            }
            return getSuggestions(selectionArgs[0]);

        default:
            throw new UnsupportedOperationException("Unknown uri: " + uri);
    }

    retCursor.setNotificationUri(getContext().getContentResolver(), uri);
    return retCursor;
}

private Cursor getSuggestions(String query) {
    query = query.toLowerCase();
    String[] columns = new String[]{
           CookingContract.FoodEntry._ID,
           CookingContract.FoodEntry.COLUMN_NAME,
           CookingContract.FoodEntry.COLUMN_DESCRIPTION,

    };
    return cookingDBHelper.getWordMatches(query, columns);
}

使用 setProjectionMap 我应该能够告诉 Android 我的列有什么名称并根据 SearchManager 约束使用它... 我做错了什么?

我认为你的投影图(mColumnMap)不正确,你的是这样的:

map.put(SearchManager.SUGGEST_COLUMN_TEXT_1, "rowid AS " +
            CookingContract.FoodEntry.COLUMN_NAME);
map.put(SearchManager.SUGGEST_COLUMN_TEXT_2, "rowid AS " +
            CookingContract.FoodEntry.COLUMN_DESCRIPTION);
map.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID, "rowid AS " + 
            CookingContract.FoodEntry._ID);

这意味着您正在按以下方式映射列:

SUGGEST_COLUMN_NAME -> rowid AS COLUMN_NAME
SUGGEST_COLUMN_TEXT_2 -> rowid AS COLUMN_DESCRIPTION
SUGGEST_COLUMN_INTENT_DATA_ID -> rowid AS _ID

当查询构建器使用您的地图时,它会将列名称重命名为地图上作为值给出的名称,但根据您在地图上作为键提供的列,none您正在查询的当前列将被正确映射。

String[] columns = new String[]{
       CookingContract.FoodEntry._ID,
       CookingContract.FoodEntry.COLUMN_NAME,
       CookingContract.FoodEntry.COLUMN_DESCRIPTION,

};

无法正确映射上面的列,因为其中 none 列作为投影图上的键存在。

可以在 this question.

上找到有关地图投影的一些示例及其有用的原因

考虑到custom suggestions上的指南,要返回的游标预计至少包含2列:_IDSUGGEST_COLUMN_TEXT_1,因此我建议您更改您的地图到以下地图:

map.put(CookingContract.FoodEntry._ID, 
            CookingContract.FoodEntry._ID + " as " + SearchManager._ID);
map.put(CookingContract.FoodEntry.COLUMN_NAME,
            CookingContract.FoodEntry.COLUMN_NAME + " as " + SearchManager.SUGGEST_COLUMN_TEXT_1);
map.put(CookingContract.FoodEntry.COLUMN_DESCRIPTION,
            CookingContract.FoodEntry.COLUMN_DESCRIPTION + " as " + SearchManager.SUGGEST_COLUMN_TEXT_2);

使用此映射,您提供的列将按以下方式映射:

FoodEntry._ID -> _ID
FoodEntry.COLUMN_NAME -> FoodEntry.COLUMN_NAME as SUGGEST_COLUMN_TEXT_1
FoodEntry.COLUMN_DESCRIPTION -> FoodEntry.COLUMN_DESCRIPTION as SUGGEST_COLUMN_TEXT_2

请注意,我省略了 SUGGEST_COLUMN_INTENT_DATA_ID 列,因为我不知道您使用哪个列来查询数据库中的单个记录,它可能是 rowId_ID,可以根据需要调整投影图

另外请确保您正在配置 your manifest 中的 android:searchSuggestIntentAction 以正确处理操作。

希望这能让我们更清楚地思考异常。