-
我有一个
ContentProvider
,它抽象了我用于填充列表CursorAdapter
的信息。 -
我正在操作栏中构建一个
SearchView
,并希望向其附加搜索ContentProvider
。 我可以为此使用相同的提供程序吗?这是好的设计吗?SearchView
内容将与#1相同,它仅用于搜索大量的项目列表视图。
ContentProvider
代码如下:
public class WebSitesContentProvider extends ContentProvider {
// database
private UserDatabaseHelper database;
// Used for the UriMacher
private static final int TOTAL_ELEMENTS = 10;
private static final int ELEMENT_ID = 20;
private static final String BASE_PATH = "websites";
public static final Uri CONTENT_URI = Uri.parse("content://" + Consts.AUTHORITY + "/" + BASE_PATH);
public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/website";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + Consts.TABLE_WEBSITES_INFO;
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(Consts.AUTHORITY, BASE_PATH, TOTAL_ELEMENTS);
sURIMatcher.addURI(Consts.AUTHORITY, BASE_PATH + "/#", ELEMENT_ID);
}
@Override
public boolean onCreate() {
database = new UserDatabaseHelper(getContext());
return false;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
// UsIng SQLiteQueryBuilder instead of query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// Check if the caller has requested a column which does not exists
checkColumns(projection);
// Set the table
queryBuilder.setTables(Consts.TABLE_WEBSITES_INFO);
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case TOTAL_ELEMENTS:
break;
case ELEMENT_ID:
// Adding the ID to the original query
queryBuilder.appendWhere(Consts.COLUMN_ID + "=" + uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase db = database.getWritableDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
// Make sure that potential listeners are getting notified
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
long id = 0;
switch (uriType) {
case TOTAL_ELEMENTS:
id = sqlDB.insert(Consts.TABLE_WEBSITES_INFO, null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_PATH + "/" + id);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
switch (uriType) {
case TOTAL_ELEMENTS:
rowsDeleted = sqlDB.delete(Consts.TABLE_WEBSITES_INFO,
selection,
selectionArgs);
break;
case ELEMENT_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete(Consts.TABLE_WEBSITES_INFO,
Consts.COLUMN_ID + "=" + id,
null);
} else {
rowsDeleted = sqlDB.delete(Consts.TABLE_WEBSITES_INFO,
Consts.COLUMN_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
/*
* Let's not notify content observers on deletes of less then 1 as each delete would cause a network call.
* user could delete multiple entries at once. if the deletes are greater then 1 then it's probably a
* request to remove the entire list, this we will allow
*/
//if(rowsDeleted>1)
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsUpdated = 0;
switch (uriType) {
case TOTAL_ELEMENTS:
rowsUpdated = sqlDB.update(Consts.TABLE_WEBSITES_INFO,
values,
selection,
selectionArgs);
break;
case ELEMENT_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update(Consts.TABLE_WEBSITES_INFO,
values,
Consts.COLUMN_ID + "=" + id,
null);
} else {
rowsUpdated = sqlDB.update(Consts.TABLE_WEBSITES_INFO,
values,
Consts.COLUMN_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
private void checkColumns(String[] projection) {
String[] available = {
Consts.COLUMN_USER,
Consts.COLUMN_ID
};
if (projection != null) {
HashSet<String> requestedColumns = new HashSet<String>(Arrays.asList(projection));
HashSet<String> availableColumns = new HashSet<String>(Arrays.asList(available));
// Check if all columns which are requested are available
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException("Unknown columns in projection");
}
}
}
}
更新
ContentProvider
是通用的,我同意这一点。它们可以进行调整。所以我调整了我的来处理SearchView
数据内容。
以下是整个ContentProvider
,它既是SearchView
内容提供商,又是ListView
光标适配器,供任何感兴趣的人使用:
package org.jefferyemanuel.database;
import java.util.Arrays;
import java.util.HashSet;
import org.jefferyemanuel.bulkwebsites.Consts;
import org.jefferyemanuel.bulkwebsites.Utils;
import android.app.SearchManager;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.BaseColumns;
import android.text.TextUtils;
import android.util.Log;
public class WebSitesContentProvider extends ContentProvider {
/* define out search provider structures */
// UriMatcher constant for search suggestions
private static final int SEARCH_SUGGEST = 1;
private static final String[] SEARCH_SUGGEST_COLUMNS = {
BaseColumns._ID,
SearchManager.SUGGEST_COLUMN_TEXT_1,
SearchManager.SUGGEST_COLUMN_INTENT_DATA,
SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA,
SearchManager.SUGGEST_COLUMN_SHORTCUT_ID
};
// database
private UserDatabaseHelper database;
// Used for the UriMacher
private static final int TOTAL_ELEMENTS = 10;
private static final int ELEMENT_ID = 20;
private static final String BASE_PATH = "websites";
public static final Uri CONTENT_URI = Uri.parse("content://" + Consts.AUTHORITY + "/" + BASE_PATH);
public static final String CONTENT_TYPE = ContentResolver.CURSOR_DIR_BASE_TYPE + "/website";
public static final String CONTENT_ITEM_TYPE = ContentResolver.CURSOR_ITEM_BASE_TYPE + Consts.TABLE_WEBSITES_INFO;
private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
static {
sURIMatcher.addURI(Consts.AUTHORITY, BASE_PATH, TOTAL_ELEMENTS);
sURIMatcher.addURI(Consts.AUTHORITY, BASE_PATH + "/#", ELEMENT_ID);
sURIMatcher.addURI(Consts.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, SEARCH_SUGGEST);
sURIMatcher.addURI(Consts.AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", SEARCH_SUGGEST);
}
@Override
public boolean onCreate() {
database = new UserDatabaseHelper(getContext());
return false;
}
@Override
public String getType(Uri uri) {
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// UsIng SQLiteQueryBuilder instead of query() method
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
// Check if the caller has requested a column which does not exists
checkColumns(projection);
// Set the table
queryBuilder.setTables(Consts.TABLE_WEBSITES_INFO);
int uriType = sURIMatcher.match(uri);
switch (uriType) {
case TOTAL_ELEMENTS:
break;
case SEARCH_SUGGEST:
queryBuilder.appendWhere(Consts.COLUMN_NAME + " LIKE '%" + uri.getLastPathSegment() + "%'");
break;
case ELEMENT_ID:
// Adding the ID to the original query
queryBuilder.appendWhere(Consts.COLUMN_ID + "=" + uri.getLastPathSegment());
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
SQLiteDatabase db = database.getWritableDatabase();
Cursor cursor = queryBuilder.query(db, projection, selection, selectionArgs, null, null, sortOrder);
/*
* If this request is from a SearchView then convert cursor to search Matrix cursor.
*/
if (uriType == SEARCH_SUGGEST)
cursor = buildSearchMatrixCursorFromStandardCursor(cursor);
// Make sure that potential listeners are getting notified
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
long id = 0;
switch (uriType) {
case TOTAL_ELEMENTS:
id = sqlDB.insert(Consts.TABLE_WEBSITES_INFO, null, values);
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return Uri.parse(BASE_PATH + "/" + id);
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsDeleted = 0;
switch (uriType) {
case TOTAL_ELEMENTS:
rowsDeleted = sqlDB.delete(Consts.TABLE_WEBSITES_INFO, selection, selectionArgs);
break;
case ELEMENT_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsDeleted = sqlDB.delete(Consts.TABLE_WEBSITES_INFO,
Consts.COLUMN_ID + "=" + id,
null);
} else {
rowsDeleted = sqlDB.delete(Consts.TABLE_WEBSITES_INFO,
Consts.COLUMN_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsDeleted;
}
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
int uriType = sURIMatcher.match(uri);
SQLiteDatabase sqlDB = database.getWritableDatabase();
int rowsUpdated = 0;
switch (uriType) {
case TOTAL_ELEMENTS:
rowsUpdated = sqlDB.update(Consts.TABLE_WEBSITES_INFO, values,
selection, selectionArgs);
break;
case ELEMENT_ID:
String id = uri.getLastPathSegment();
if (TextUtils.isEmpty(selection)) {
rowsUpdated = sqlDB.update(Consts.TABLE_WEBSITES_INFO, values,
Consts.COLUMN_ID + "=" + id,
null);
} else {
rowsUpdated = sqlDB.update(Consts.TABLE_WEBSITES_INFO, values,
Consts.COLUMN_ID + "=" + id + " and " + selection,
selectionArgs);
}
break;
default:
throw new IllegalArgumentException("Unknown URI: " + uri);
}
getContext().getContentResolver().notifyChange(uri, null);
return rowsUpdated;
}
private void checkColumns(String[] projection) {
String[] available = { Consts.COLUMN_NAME, Consts.COLUMN_ID };
if (projection != null) {
HashSet<String> requestedColumns = new HashSet<String>(Arrays.asList(projection));
HashSet<String> availableColumns = new HashSet<String>(Arrays.asList(available));
// Check if all columns which are requested are available
if (!availableColumns.containsAll(requestedColumns)) {
throw new IllegalArgumentException("Unknown columns in projection");
}
}
}
/*
* KEY METHOD THAT USES THE DATA FROM DATABASE THAT LISTVIEW ALSO USES
* TO CREATE A MATRIX CURSOR TO SEND BACK TO SEARCHVIEW
*/
private Cursor buildSearchMatrixCursorFromStandardCursor(Cursor cursor) {
MatrixCursor cursorSearch = new MatrixCursor(SEARCH_SUGGEST_COLUMNS);
int id = 0;
int index = cursor.getColumnIndex(Consts.COLUMN_NAME);
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
String name = cursor.getString(index);
cursorSearch.addRow(new String[] {
String.valueOf(++id),
name,
name,
name,
SearchManager.SUGGEST_NEVER_MAKE_SHORTCUT
});
cursor.moveToNext();
}
return cursorSearch;
}
}
您正在使用的内容提供程序是通用的,可用于搜索功能。
起初你可能会想,也许你应该写一个专门用于搜索的内容提供程序,但是:
- 您将不得不复制大量代码。
- 内容提供者不是为了具体而设计的,它们只是抽象了对数据的访问。
您的"搜索内容提供商"将用于进行查询,并且您已经拥有内容提供商。
内容提供程序不需要特定于搜索。另一方面,您的助手应该是具体的。