Android 组件ContentProvider(一)内容提供器
1. ContentProvider内容提供器
内容提供器可以让不同的应用程序之间实现数据共享的功能,允许一个程序访问另外一个程序中的数据,同时保证被访问数据的安全性,而之前的数据持久化而保存的数据只能是能被当前的应用程序使用。
文件存储和SharedPreferences存储可以实现全局读写操作模式,内容提供器可以选择对一部分数据进行共享,从而保证隐私数据不会有泄露的风险。
2. 运行时权限
说到内容提供器,在Android系统中本身就提供了很多的内容提供器,比如联系人,短信,日历等,既要是实现一个应用程序访问另一个应用程序的共享数据,又要保证数据的隐私安全,就不得不涉及到访问的权限,运行时权限是Android6.0加入的改进的权限申请机制,运行时权限功能避免用户一次性授权所有申请权限,可以在使用的过程中再进一步授权。这个可分为两类:1、普通权限;2、危险权限。
Android应用程序清单里添加权限。
在Intent中添加申请权限。
3. 访问其他程序中的数据
内容提供器提供的两种方法:1、现有的内容提供器;2、自定义的内容提供器。
a. ContentResolver
应用程序想要访问内容提供器中的共享数据,就要使用ContentResolver这个类,通过Context中的getContentResolver()方法获取该类的实例。
ContentResolver类提供一些方法进行CRUD数据操作。在这些操作中ContentResolver是不接收表名的参数的,而是接收Uri参数代替,URI给内容提供器中的数据建立了唯一标识符 。
i. Uri包括authority和path。authority是对不同应用程序做区分(会使用包名来进行命名),path是对同一应用程序不同的表做区分,有的还会存在id。”content:”是用来标识数据是由Content Provider管理的 schema。
Uri uri=Uri.parse(“content://com.example.app.provider/table1”)
Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
ii. ContentValues 添加数据。这个和SQLite的添加数据方式一样。
b. 自定义内容提供器
通过上面的学习我们知道,向外访问其他应用程序的数据,只需获取该程序的内容URI,再利用ContentResolver进行CRUD操作就可以了。
那问题来了,那些 提供外部访问接口的应用程序是怎么实现这个功能的呢?怎么保证数据安全隐私不被泄露呢?
实现跨程序共享数据的功能,要新建一个类去继承ContentProvider类创建自己的内容提供器,并重写类中6个抽象方法。
//创建UriMatcher类,利用match()方法来匹配传入的URI的功能,
// static中先定义了可以被访问的数据的路径
public static final String AUTHORITY = "com.example.databasetest.provider";
private static UriMatcher uriMatcher;
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("AUTHORITY", "book", BOOK_DIR);
uriMatcher.addURI("AUTHORITY", "book/#", BOOK_ITEM);
uriMatcher.addURI("AUTHORITY", "category", CATEGORY_DIR);
uriMatcher.addURI("AUTHORITY", "table2/#", CATEGORY_ITEM);
}
//继承ContentProvider类要重写的6个方法,方法里访问数据的操作和SQLite里的操作一样
@Override
public boolean onCreate(){
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = null;
switch (uriMatcher.match(uri)) {
case BOOK_DIR:
cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder);
break;
case BOOK_ITEM:
//getPathSegments()将URI分成列表第0个位置存放Uri路径,第1个存放id
String bookId = uri.getPathSegments().get(1);
cursor = db.query("Book", projection, "id=?", new String[]{bookId}, null, null, sortOrder);
break;
case CATEGORY_DIR:
cursor = db.query("Category", projection, selection, selectionArgs, null, null, sortOrder);
break;
case CATEGORY_ITEM:
String categoryId = uri.getPathSegments().get(1);
cursor = db.query("Category", projection, "id=?", new String[]{categoryId}, null, null, sortOrder);
break;
default:
break;
}
return cursor;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public String getType(Uri uri) {
return null;
}
URI所对应的MIME字符串3部分组成:vnd开头;Uri以路径结尾 android.cursor.dir/
,如以id结尾 android.cursor.item/;最后接上vnd.<authority>.<path>
。如vnd.android.cursor.dir/vnd.com.example.app.provider.table1
c. AndroidManifest.xml注册provider
<provider
android:name=".DatabaseProvider"
android:authorities="com.example.databasetest.provider"
android:enabled="true"
<!--允许外部应用程序访问这个内容提供器-->
android:exported="true" >
</provider>
d. 获取内容提供器中的数据就要使用到ContentResolver中的CRUD操作
Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));
}
cursor.close();
//更新数据和SQLite中使用到的更新的方法和相似,
Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
ContentValues values = new ContentValues();
values.put("name", "aaaa");
values.put("author", "jack");
values.put("pages", 1040);
values.put("price", 111);
Uri newUri = getContentResolver().insert(uri, values);
newId = newUri.getPathSegments().get(1);