四大组件之一,但我却没有一次尝试过,只是曾经在文档中看到过这么个东西,为了弥补自己的遗憾,特此记录下本次尝试。 虽然只有查看和添加,但删除和更新的方法也都实现了,并且内容全部写死了,可以通过 Button 的点击事件来查看。CP-demo 可实现增删改查,cp-2只写了查看。demo 地址写在最后。
内容提供程序以一个或多个表的形式将数据呈现给外部应用,这些表与关系型数据库中的表类似。行表示提供程序收集的某种类型数据的实例,行中的每一列表示为一个实例所收集的单个数据。
因此,看过了介绍之后感觉这就是共享数据库(不知道我理解的对不对)。而大部分我们需要的都是读取其他应用,如通讯录等。本文自定义的 MyProvider 也就是实现对数据库的增删改查。
public class MyProvider extends ContentProvider {private static final String TAG = "MyProvider";private static final int TITTLE = 1;private static final int TITTLE_ID = 2;private static final UriMatcher uriMatcher = getUriMatcher();private static final String DATABASE_TABLE = "test";private static UriMatcher getUriMatcher() {UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);uriMatcher.addURI(Constants.PROVIDER_NAME, "test", TITTLE);uriMatcher.addURI(Constants.PROVIDER_NAME, "test/#", TITTLE_ID);return uriMatcher;}private DBHelper dbHelper = null;private SQLiteDatabase database = null;@Overridepublic boolean onCreate() {Context context = getContext();dbHelper = new DBHelper(context);database = dbHelper.getWritableDatabase();return true;}@Nullable@Overridepublic Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,@Nullable String[] selectionArgs, @Nullable String sortOrder) {Cursor cursor = null;switch (uriMatcher.match(uri)) {case TITTLE_ID:cursor = database.query(DATABASE_TABLE, projection, "_id = ",new String[]{uri.getPathSegments().get(1)}, null,null, sortOrder);break;case TITTLE:cursor = database.query(DATABASE_TABLE, projection, selection, selectionArgs, null,null, sortOrder);break;default:throw new IllegalArgumentException("Unknown URI " + uri);}return cursor;}/*** 关于MIME类型,android 是这么规定的。* 1.必须以vnd开头* 2.如果是多条记录,后面接android.cursor.dir/,如果是单条记录,后面接android.cursor.item/* 3.最后 加上"vnd.<authority>.<path>"** @param uri* @return*/@Nullable@Overridepublic String getType(@NonNull Uri uri) {switch (uriMatcher.match(uri)) {case TITTLE:return "vnd.android.cursor.dir/vnd.com.flyscale.cp.data";case TITTLE_ID:return "vnd.android.cursor.item/vnd.com.flyscale.cp.data";default:throw new IllegalArgumentException("Unsupported URI: " + uri);}}@Nullable@Overridepublic Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {long rowId = database.insert(DATABASE_TABLE, null, contentValues);if (rowId > 0) {Uri mUri = ContentUris.withAppendedId(uri, rowId);return mUri;}throw new SQLException("Failed to insert row into " + uri);}@Overridepublic int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {int rowIDs;switch (uriMatcher.match(uri)) {case TITTLE_ID:String tittleID = uri.getPathSegments().get(1);rowIDs = database.delete(DATABASE_TABLE, "_id = ", new String[]{tittleID});break;case TITTLE:rowIDs = database.delete(DATABASE_TABLE, selection, selectionArgs);break;default:throw new IllegalArgumentException("Unknown URI " + uri);}return rowIDs;}@Overridepublic int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String selection, @Nullable String[] selectionArgs) {int rowIDs;Log.e(TAG, "query: " + uriMatcher.match(uri));switch (uriMatcher.match(uri)) {case TITTLE_ID:String tittleID = uri.getPathSegments().get(1);rowIDs = database.update(DATABASE_TABLE, contentValues, "_id = ", new String[]{tittleID});break;case TITTLE:rowIDs = database.update(DATABASE_TABLE, contentValues, selection, selectionArgs);break;default:throw new IllegalArgumentException("Unknown URI " + uri);}return rowIDs;}
}
调用方法的过程涉及到两个类。
ContentValues类和Bundle类很类似,都是使用HashMap的泛型形式来存储的,只能存储基本类型的数据。ContentResolver,具体的实现过程通过该类。
增
contentValues.put("tittle", "Hello world"); Uri uri = contentResolver.insert(Constants.CONTENT_URI, contentValues);
删
int cursor = contentResolver.delete(Constants.CONTENT_URI,null, null);
改
contentValues.clear(); contentValues.put("tittle", "Hello world - 改"); int cursor2 = contentResolver.update(Constants.CONTENT_URI, contentValues, null, null);
查
Cursor cursor3 = contentResolver.query(Constants.CONTENT_URI,null, null, null, null); while(cursor3.moveToNext()) {Log.d(TAG, "initView: " + cursor3.getString(cursor3.getColumnIndex("tittle"))); } cursor3.close();
在官网看到的ContentResolver.query() 方法:
// Queries the user dictionary and returns results cursor = getContentResolver().query(UserDictionary.Words.CONTENT_URI, // The content URI of the words tableprojection, // The columns to return for each rowselectionClause, // Selection criteriaselectionArgs, // Selection criteriasortOrder); // The sort order for the returned rows
Query() 与 SQL 查询的比较。
query() 参数 SELECT 关键字/参数 备注 Uri
FROM table_name
Uri
映射至提供程序中名为 table_name 的表。projection
col,col,col,...
projection
是检索到的每个行所应包含的列的数组。selection
WHERE col = value
selection
指定选择行的条件。selectionArgs
(没有完全等效项,选择参数会替换选择子句中的 ?
占位符。)sortOrder
ORDER BY col,col,...
sortOrder
指定在返回的中各行的显示顺序。
Cursor
上述的方法通过 contentResolver 调用内容提供器的功能,实质上则是通过 Content Provide 来实现的。在 MyProvider 已实现具体功能。为了方便,表名为 test , 只有一个 tittle。下面的是导出来的 db 文件。
public class DBHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "data.db";private static final String TABLE_NAME = "test";private static final String SQL_CREATE = "CREATE TABLE " + TABLE_NAME +" (_id INTEGER PRIMARY KEY, tittle TEXT )";private static final String SQL_DROP = "DROP TABLE IS EXISTS " + TABLE_NAME ;public DBHelper(Context context) {super(context, DATABASE_NAME, null, 1);}@Overridepublic void onCreate(SQLiteDatabase sqLiteDatabase) {sqLiteDatabase.execSQL(SQL_CREATE);}@Overridepublic void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {sqLiteDatabase.execSQL(SQL_DROP);onCreate(sqLiteDatabase);}public Cursor getData(String id, String[] projection, String selection, String[] selectionArgs, String sortOrder) {SQLiteQueryBuilder sqliteQueryBuilder = new SQLiteQueryBuilder();sqliteQueryBuilder.setTables(TABLE_NAME);if(id != null) {sqliteQueryBuilder.appendWhere("_id" + " = " + id);}if(TextUtils.isEmpty(sortOrder)) {sortOrder = "tittle";}Cursor cursor = sqliteQueryBuilder.query(getReadableDatabase(),projection,selection,selectionArgs,null,null,sortOrder);return cursor;}
}
最后需要在清单文件中注册,authorities 是 provider所在的包的名字 + provider 本身定义的名称。
<providerandroid:authorities="com.flyscale.cp.data"android:name=".MyProvider"android:exported="true" />
对了不要忘记权限声明
<uses-permission android:name="android.permission.READ_USER_DICTIONARY"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
传送门:ContentProvider demo