实现基本内容提供程序类

1)创建合同类

契约类定义了有助于应用程序使用内容 URI,列名,意图操作和内容提供程序的其他功能的常量。合同类不会自动包含在提供者中; 提供者的开发者必须定义它们,然后将它们提供给其他开发人员。

提供者通常具有单个权限,该权限用作其 Android 内部名称。为避免与其他提供程序冲突,请使用唯一的内容权限。由于此建议对于 Android 程序包名称也是如此,因此你可以将提供程序权限定义为包含提供程序的程序包名称的扩展名。例如,如果你的 Android 软件包名称为 com.example.appname,则应该向你的提供商授予权限 com.example.appname.provider

public class MyContract {
    public static final String CONTENT_AUTHORITY = "com.example.myApp";
    public static final String PATH_DATATABLE = "dataTable";
    public static final String TABLE_NAME = "dataTable";
}

内容 URI 是标识提供者中的数据的 URI。内容 URI 包括整个提供程序的符号名称(其权限)以及指向表或文件(路径)的名称。可选的 id 部分指向表中的单个行。ContentProvider 的每个数据访问方法都有一个内容 URI 作为参数; 这允许你确定要访问的表,行或文件。在合同类中定义它们。

public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_DATATABLE).build();

// define all columns of table and common functions required

2)创建助手类

帮助程序类管理数据库创建和版本管理。

public class DatabaseHelper extends SQLiteOpenHelper {

    // Increment the version when there is a change in the structure of database
    public static final int DATABASE_VERSION = 1;
    // The name of the database in the filesystem, you can choose this to be anything
    public static final String DATABASE_NAME = "weather.db";

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // Called when the database is created for the first time. This is where the
        // creation of tables and the initial population of the tables should happen.
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // Called when the database needs to be upgraded. The implementation
        // should use this method to drop tables, add tables, or do anything else it
        // needs to upgrade to the new schema version.
    }
}

3)创建一个扩展 ContentProvider 类的类

public class MyProvider extends ContentProvider {

public DatabaseHelper dbHelper;

public static final UriMatcher matcher = buildUriMatcher();
public static final int DATA_TABLE = 100;
public static final int DATA_TABLE_DATE = 101;

UriMatcher 将权限和路径映射到整数值。方法 match() 为 URI 返回一个唯一的整数值(它可以是任意数字,只要它是唯一的)。switch 语句在查询整个表和查询单个记录之间进行选择。如果 URI 是表的内容 URI,则我们的 UriMatcher 返回 100;如果 URI 指向该表中的特定行,则返回 101。你可以使用 # 通配符匹配任何数字和*以匹配任何字符串。

public static UriMatcher buildUriMatcher() {
    UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    uriMatcher.addURI(CONTENT_AUTHORITY, MyContract.PATH_DATATABLE,        DATA_TABLE);
    uriMatcher.addURI(CONTENT_AUTHORITY, MyContract.PATH_DATATABLE + "/#", DATA_TABLE_DATE);
    return uriMatcher;
}

重要提示: addURI() 调用的顺序很重要! UriMatcher 将从第一个添加到最后一个按顺序查看。由于像 #*这样的通配符很贪婪,因此你需要确保已正确地订购了 URI。例如:

uriMatcher.addURI(CONTENT_AUTHORITY, "/example", 1);
uriMatcher.addURI(CONTENT_AUTHORITY, "/*",       2);

是正确的排序,因为匹配器将首先寻找/example,然后才能使用/*匹配。如果这些方法调用被反转并且你调用了 uriMatcher.match("/example"),那么 UriMatcher 一旦遇到/*路径就会停止寻找匹配并返回错误的结果!

然后,你需要覆盖这些功能:

onCreate() :初始化你的提供者。Android 系统在创建提供程序后立即调用此方法。请注意,在 ContentResolver 对象尝试访问它之前,不会创建提供程序。

@Override
public boolean onCreate() {
    dbhelper = new DatabaseHelper(getContext());
    return true;
}

getType() :返回与内容 URI 对应的 MIME 类型

@Override
public String getType(Uri uri) {
    final int match = matcher.match(uri);
    switch (match) {
        case DATA_TABLE:
            return ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + MyContract.CONTENT_AUTHORITY + "/" + MyContract.PATH_DATATABLE;
        case DATA_TABLE_DATE:
            return ContentResolver.ANY_CURSOR_ITEM_TYPE + "/" + MyContract.CONTENT_AUTHORITY + "/" + MyContract.PATH_DATATABLE;
        default:
            throw new UnsupportedOperationException("Unknown Uri: " + uri);

    }
}

query() :从提供者中检索数据。使用参数选择要查询的表,要返回的行和列以及结果的排序顺序。将数据作为 Cursor 对象返回。

@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    Cursor retCursor = dbHelper.getReadableDatabase().query(
        MyContract.TABLE_NAME, projection, selection, selectionArgs, null, null, sortOrder);
    retCursor.setNotificationUri(getContext().getContentResolver(), uri);
    return retCursor;
}

在你的提供程序中插入一个新行。使用参数选择目标表并获取要使用的列值。返回新插入行的内容 URI。

@Override
public Uri insert(Uri uri, ContentValues values)
{
    final SQLiteDatabase db = dbHelper.getWritableDatabase();
    long id = db.insert(MyContract.TABLE_NAME, null, values);
    return ContentUris.withAppendedId(MyContract.CONTENT_URI, ID);
}

delete() :从提供者中删除行。使用参数选择表和要删除的行。返回已删除的行数。

@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    int rowsDeleted = db.delete(MyContract.TABLE_NAME, selection, selectionArgs);
    getContext().getContentResolver().notifyChange(uri, null);
    return rowsDeleted;
}

update() :更新提供程序中的现有行。使用参数选择要更新的表和行以及获取新列值。返回更新的行数。

@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    int rowsUpdated = db.update(MyContract.TABLE_NAME, values, selection, selectionArgs);
    getContext().getContentResolver().notifyChange(uri, null);
    return rowsUpdated;
}

4)更新清单文件

<provider
        android:authorities="com.example.myApp"
        android:name=".DatabaseProvider"/>