ContentProvider 对应用之间数据访问起着很重要的作用,比如我们在自己的应用中去获取联系人信息,相册图片等
文中主要涉及的知识点
- UriMatcher
- SQLiteOpenHelper
- ContentProvider
- ContentProvider配置权限等
开始之前,建议将外部访问的Uri参数进行常量化
先来看看Uri格式
Authority: 授权信息,用以区别不同的ContentProvider;
Path: 表名,用以区分ContentProvider中不同的数据表;
Id: Id号,用以区别表中的不同数据;
进行常量定义如下:
public class MyContract {
public static final String CONTENT_AUTHORITY = "com.yeaper.contentproviderdemo";
public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);
public static final String PATH_TEST = "test";
public static final class TestEntry implements BaseColumns {
public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_TEST).build();
public static Uri buildUri(long id) {
return ContentUris.withAppendedId(CONTENT_URI, id);
}
public static final String TABLE_NAME = "test";
public static final String COLUMN_NAME = "name";
}
}
一、UriMatcher
主要用于匹配外部访问时,传进来的 Uri
final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
final String authority = MyContract.CONTENT_AUTHORITY;
matcher.addURI(authority, MyContract.PATH_TEST, code);
addURI(authority, MyContract.PATH_TEST, TEST);
- 这行代码是添加外部访问路径,可添加多个
matcher.match(uri)
- 会将 uri 和 addUri 方法添加的 uri 进行匹配,返回对应 code,再进行数据操作
二、SQLiteOpenHelper
自定义数据库助手类,完成数据库相关操作
public class MyDBOpenHelper extends SQLiteOpenHelper {
/**
*
* @param context 上下文
* @param db_name 数据库名
* @param db_version 数据库版本
*/
public MyDBOpenHelper(Context context, String db_name, int db_version) {
super(context, db_name, null, db_version);
}
@Override
public void onCreate(SQLiteDatabase db) {
// 创建表的语句
final String SQL_CREATE_CONTACT_TABLE = "CREATE TABLE " + MyContract.TestEntry.TABLE_NAME + "( "
+ MyContract.TestEntry._ID + " TEXT PRIMARY KEY, "
+ MyContract.TestEntry.COLUMN_NAME + " TEXT NOT NULL );";
db.execSQL(SQL_CREATE_CONTACT_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + MyContract.TestEntry.TABLE_NAME);
onCreate(db);
}
}
三、ContentProvider
- 自定义 ContentProvider,实现它的六个方法,其中 insert、delete、query、update 对应数据库的增删查改
- 外部 APP 使用 ContentResolver 时会传进 Uri,进行四大操作之前先通过UriMatcher进行匹配,通过即可进行操作
public class MyContentProvider extends ContentProvider {
private MyDBOpenHelper mOpenHelper;
@Override
public boolean onCreate() {
mOpenHelper = new MyDBOpenHelper(getContext(), "contact.db", 1001);
return true;
}
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
@Nullable
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
Cursor cursor = null;
switch ( buildUriMatcher().match(uri)) {
case TEST:
cursor = db.query(MyContract.TestEntry.TABLE_NAME, projection, selection, selectionArgs, sortOrder, null, null);
break;
}
return cursor;
}
@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
Uri returnUri;
long _id;
switch ( buildUriMatcher().match(uri)) {
case TEST:
_id = db.insert(MyContract.TestEntry.TABLE_NAME, null, values);
if ( _id > 0 )
returnUri = MyContract.TestEntry.buildUri(_id);
else
throw new android.database.SQLException("Failed to insert row into " + uri);
break;
default:
throw new android.database.SQLException("Unknown uri: " + uri);
}
return returnUri;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
private final static int TEST = 100;
static UriMatcher buildUriMatcher() {
final UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);
final String authority = MyContract.CONTENT_AUTHORITY;
matcher.addURI(authority, MyContract.PATH_TEST, TEST);
return matcher;
}
}
四、ContentProvider配置权限等
- 注册ContentProvider
<provider
android:authorities="com.yeaper.contentproviderdemo"
android:name=".provider.MyContentProvider"/>
想让外部 APP 能访问到,需要给 provider 配置属性
android:readPermission="com.yeaper.contentproviderdemo.READ"
android:writePermission="com.yeaper.contentproviderdemo.WRITE"
android:exported="true"
并申明读写权限
<permission android:name="com.yeaper.contentproviderdemo.READ" android:protectionLevel="normal"/>
<permission android:name="com.yeaper.contentproviderdemo.WRITE" android:protectionLevel="normal"/>
其中,android:exported 属性让provider可以被外界访问,权限可以控制外部对本应用内数据的操作权限,还有其他属性就不介绍了
最后,外部使用如下:
先添加读写权限,注意,这里是 uses-permission 标签
<uses-permission android:name="com.yeaper.contentproviderdemo.READ" />
<uses-permission android:name="com.yeaper.contentproviderdemo.WRITE"/>
然后使用 ContentResolver 传进 Uri 进行数据操作,此处的 Uri 就是前面定义的常量
Uri uri = Uri.parse("content://com.yeaper.contentproviderdemo/test");
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if(cursor == null) return;
try {
other_data.setText("total data number = " + cursor.getCount());
} finally {
cursor.close();
}