【问题标题】:Dual purpose of Android ContentProvider: 1. Search provider and 2. List content providerAndroid ContentProvider 的双重用途:1. 搜索提供者和 2. 列出内容提供者
【发布时间】:2013-09-05 20:29:54
【问题描述】:
  1. 我有一个 ContentProvider 抽象了我用于 CursorAdapter 的信息以填充列表。

  2. 我正在操作栏中构建一个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");
            }
        }
    }
}

更新

ContentProviders 是通用的,我同意这一点。 他们可以适应。 所以我调整了我的来处理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;
    }
}

【问题讨论】:

    标签: android search android-contentprovider searchview


    【解决方案1】:

    您使用的 ContentProvider 是通用的,可用于搜索功能。

    一开始你可能会想,也许你应该编写一个专门用于搜索的 ContentProvider,但是:

    • 您将不得不复制大量代码。
    • ContentProvider 并非专为特定而设计的,它们只是抽象了对数据的访问。

    您的“搜索内容提供者”将用于进行查询,而您已经拥有该内容提供者。

    ContentProvider 不需要专门用于搜索。 另一方面,您的 Adpater 应该是具体的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多