我想在使用SearchView时从我的数据库表中获取建议。
我得 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约束... 我做错了什么?
答案 0 :(得分:0)
我认为您的投影地图(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
当查询构建器使用您的地图时,它会将列名重命名为地图上的值,但根据您在地图上作为键提供的列,您查询的当前列都不会正确映射。
String[] columns = new String[]{
CookingContract.FoodEntry._ID,
CookingContract.FoodEntry.COLUMN_NAME,
CookingContract.FoodEntry.COLUMN_DESCRIPTION,
};
上面的列无法正确映射,因为它们都不是投影图上的键。
有关地图投影的一些示例及其有用的原因可以在this question上找到。
考虑到custom suggestions上的指南,要返回的光标应至少包含2列:_ID
和SUGGEST_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
以正确处理操作。
希望这使得对异常的思考更加清晰。