1

SQLite 结构

Table: Class

 Column1: classID (primary key)
 Column2: className


Table: Students

 Column1: studentID (primary key)
 Column2: classID (foreign key)
 Column3: studentName

问题

我遵循了添加自定义建议开发人员指南。当我在操作栏搜索小部件中键入内容时,系统正确调用了我的内容提供者的查询功能,并且我可以看到搜索建议。我的问题是查询返回来自整个学生表的建议(这是预期的行为)。但我需要限制给定 classID 的建议。但是搜索建议的工作方式如开发人员指南中所述,只有一个参数传递给查询函数,在我的例子中是 selectionArgs[0]。

可搜索的.xml

<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:hint="@string/student_search_hint"
    android:label="@string/app_name"
    android:searchSuggestThreshold="2"
    android:searchSuggestAuthority="com.androidapp.providers.database"
    android:searchSuggestSelection="studentName LIKE ? "
    android:searchSuggestIntentAction="android.intent.action.VIEW"
    android:searchMode="queryRewriteFromText" >

内容提供者的摘录

@Override
public Cursor query(Uri uri, String[] projection, String selection,String[], selectionArgs, String sortOrder) {

    ...

    queryBuilder.setTables(StudentsTable.TABLE);

    HashMap<String, String> columnMap = new HashMap<String, String>();
    columnMap.put(BaseColumns._ID, StudentsTable.STUDENT_ID + " AS " + BaseColumns._ID);
    columnMap.put(SearchManager.SUGGEST_COLUMN_TEXT_1, StudentsTable.NAME + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_1);
    columnMap.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA, StudentsTable.STUDENT_ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA);
    queryBuilder.setProjectionMap(columnMap);

    limit = uri.getQueryParameter(SearchManager.SUGGEST_PARAMETER_LIMIT);
    selectionArgs[0] = "%"+selectionArgs[0] + "%";

    SQLiteDatabase db = database.getWritableDatabase();
    Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder, limit);

    return cursor;
}

如果查询是由我发起的,我可以简单地在 selectionArgs[1] 中传递第二个参数(classID)并适当地修改选择字符串以形成正确的 SQLite 语句。

但是查询是由系统发起的。那么我该怎么做呢?是否可以拦截对我的内容提供者的调用并修改对查询的调用?

4

2 回答 2

1

我希望这对某人有所帮助,我花了几天时间试图弄清楚这一点,感谢 pskink 提供的链接,我能够实现以下解决方案:

我在内容提供程序中创建了一个变量和一个适当的 setter 方法:

public class MyContentProvider extends ContentProvider {

    ...

    private long id;

    ...

    public void setId(long id) {
        this.id = id;     
    }

}

然后在我只想为特定班级的学生提供搜索建议的活动中,我这样做:

ContentProviderClient client = getContentResolver().acquireContentProviderClient("com.androidapp.providers.database");
MyContentProvider provider = (MyContentProvider)client.getLocalContentProvider();
provider.setId(rowid); //rowid is the classId from which students will be searched
client.release();

修改查询功能:

@Override
public Cursor query(Uri uri, String[] projection, String selection,String[], selectionArgs, String sortOrder) {

    ...

    queryBuilder.setTables(StudentsTable.TABLE);

    HashMap<String, String> columnMap = new HashMap<String, String>();
    columnMap.put(BaseColumns._ID, StudentsTable.STUDENT_ID + " AS " + BaseColumns._ID);
    columnMap.put(SearchManager.SUGGEST_COLUMN_TEXT_1, StudentsTable.NAME + " AS " + SearchManager.SUGGEST_COLUMN_TEXT_1);
    columnMap.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA, StudentsTable.STUDENT_ID + " AS " + SearchManager.SUGGEST_COLUMN_INTENT_DATA);
    queryBuilder.setProjectionMap(columnMap);

    limit = uri.getQueryParameter(SearchManager.SUGGEST_PARAMETER_LIMIT);
    selectionArgs[0] = "%" + selectionArgs[0] + "%";

    /*AMMENDMENT*/
    selection = selection + "AND " + StudentsTable.CLASS_ID + "=" + id;
    //This forms the SQL statement "WHERE studentName LIKE ? AND classId=3" (Assuming that rowid was 3).
    //As per normal Android behaviour the "?" mark will be replaced by selectionArgs[0].
    /*END*/

    SQLiteDatabase db = database.getWritableDatabase();
    Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder, limit);

    return cursor;
}
于 2013-12-02T05:51:41.197 回答
0

我刚刚为我的内容提供者的第二个参数创建了一个静态变量,并从活动中设置它。我一直在考虑它,这是我找到的最干净的解决方法!

于 2014-09-19T11:01:26.350 回答