四大组件之一,但我却没有一次尝试过,只是曾经在文档中看到过这么个东西,为了弥补自己的遗憾,特此记录下本次尝试。 虽然只有查看和添加,但删除和更新的方法也都实现了,并且内容全部写死了,可以通过 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;
@Override
public boolean onCreate() {
Context context = getContext();
dbHelper = new DBHelper(context);
database = dbHelper.getWritableDatabase();
return true;
}
@Nullable
@Override
public 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
@Override
public 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
@Override
public 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);
}
@Override
public 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;
}
@Override
public 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 table projection, // The columns to return for each row selectionClause, // Selection criteria selectionArgs, // Selection criteria sortOrder); // 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);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(SQL_CREATE);
}
@Override
public 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 本身定义的名称。
<provider android: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"/>