内容提供器
思维导图
最近在练习使用思维导图,献一下丑。。。
什么是内容提供器
内容提供器主要用于在不同应用程序间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序里的数据,同时还能保证被访问数据的安全性。内容提供器可以选择要分享的数据,保证应用程序的隐私数据。一般有两种内容提供器的用法:
- 一个是使用现有的内容提供器来读取和操作相应程序中的数据。
- 创建自己的内容提供器给自己的应用程序数据提供外部访问接口。
访问其他程序中的数据
ContentResolver的基本用法
获取实例
Context.getContentResolver();
getContentResolver()
方法可以获取一个ContentResolver的实例。
通过ContentResolver实例对数据进行操作
ContentResolver
对数据也有CRUD这些操作。不过不同于SQLiteDatabase,这几个方法并不接受数据库表名,使用一个Uri
参数代替了表名,内容Uri给内容提供器中的数据建立了一个唯一标识符,由权限和路径两部分构成。
权限是用于对不同应用程序进行区分的,一般会采用程序包名来进行命名。
路径则是对同一应用程序的不同表做区分。一般还要在头部加上协议声明,下面是一个示例:
content://com.example/app/provider/table
获取Uri对象的方法:
Uri uri = Uri.parse("content://com.example/app/provider/table");
-
查询
Cursor cursor = getContentResolver.query(Uri, projection,selection,selectionArgs,sortOrder);
同样返回一个Cursor对象。
参数:uri(指定查询位置),projection(指定查询的列名),selection(指定where的约束条件),selectionArgs(为where中的占位符提供值),sortOrder(指定查询结果的排列顺序)。
-
增加
//插入一条姓名hello年龄10岁的数据 ContentValue values = new ContentValue(); values.put("name", "hello"); values.put("age", 10); getContentResolver.insert(uri, values);
-
删除
//删除姓名为hello的数据 getContentReslover.delete(uri, "name = ?", new String[] {"hello"});
-
更新
//更新姓名 ContentValue values = new ContentValue(); values.put("name", "haha"); getContentReslover.update(uri, values, "name = ? and age = ?", new String[] {"haha", "10"});
小实践:读取系统联系人
-
获取Cursor对象
Cursor cursor = null; try { //获取用来遍历的cursor对象 cursor = getContentResolver.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null,null); } catch (Exception e) { e.printStackTrace(); } finally { if(cursor != null) { cursor.close(); } }
ContactsContract.CommonDataKinds.Phone.CONTENT_URI
是我们要读取的Uri的封装变量,来自于ContactsContract.CommonDataKinds.Phone类。 -
遍历读取每行数据
while(cursor.moveToNext()) { //获取联系人姓名 String name = cursor.getString(cursor.getColumnIndex( ContactsContract.CommonDataKinds.Phone.Number)); }
-
对数据进行操作
//操作吧。。。随意操作。
创建自己的内容提供器
-
创建内容提供器继承自
ContentProvider
类public class MyProvider extends ContentProvider { @Override public boolean onCreate() { return false; } @Nullable @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { return null; } @Nullable @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; } @Nullable @Override public String getType(Uri uri) { return null; } }
这六个方法是必须要实现的
onCreate()
:初始化内容提供器的时候调用,通常会在这里完成对数据库的创建和升级操作
返回值对应了创建和升级操作的成功与否。只有当ContentResolver访问我们的数据时,内容提供器才会被初始化。query()
:uri指定查询表名,projection用于确定是哪些列,selection代表约束,selectionArgs代表约束里占位符的值,sortOrder确定查询返回数据的排列顺序。insert()
:uri指定插入表名,values携带数据,返回一个用于表示这条新纪录的Uri对象update()
:uri指定更新表名,valuse携带要更新的数据,selection代表约束,selectionArgs代表约束里占位符的值。返回更新的行号delete()
:uri指定更新表名,selection代表约束,selectionArgs代表约束里占位符的值。返回被删除的行数。getType()
:根据传入的内容Uri返回相应的MIME类型。query()
这里query需要返回一个cursor,怎么去根据传入的参数去确认要返回的cursor呢,这里就用到了UriMatcher来对传入的uri进行匹配,剩下的内容就很容易了。
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { Cursor cursor = null; switch (uriMatcher.match(uri)) { case TABLE1_DIR: SQLiteDatabase database = break; case TABLE1_ITEM: break; case TABLE2_DIR: break; case TABLE2_ITEM: break; default: break; } return cursor; }
getType()
getType是provider里面必须要实现的一个方法,这里返回一个MIME类型的字符串。
public String getType(Uri uri) {
switch (uriMatcher.match(uri)) {
case TABLE1_DIR:
return "vnd.android.cursor.dir/vnd.com.learn.app.provider.table1";
break;
case TABLE1_ITEM:
return "vnd.android.cursor.item/vnd.com.learn.app.provider.table1";
break;
default:
return null;
break;
}
return null;
} MIME类型由三个部分组成:- 必须以vnd开头
- 如果uri是以路径结尾,则后接.android.cursor.dir/如果以ID结尾,则后接.android.cursor.item/
- 最后接上vnd.<authority>.<path>
例如
content://com.hello.app.provider.table
这个Uri对应的MIME 字符串就是:
vnd.android.cursor.dir/vnd.com.hello.app.provider.table
public String getType(Uri uri) { switch (uriMatcher.match(uri)) { case TABLE1_DIR: return "vnd.android.cursor.dir/vnd.com.learn.app.provider.table1"; break; case TABLE1_ITEM: return "vnd.android.cursor.item/vnd.com.learn.app.provider.table1"; break; default: return null; break; } return null; }
实现跨程序数据共享
这一节写了很多代码,但是核心的点就是在于自定义的ContentProvider里面那六个方法分别的具体实现。
1.实现自己的Provider以后其他应用就可以通过这个provider来读取我们的数据。这里算是上面内容的一个结合吧。需要注意的有几个点:
query()
方法里访问单条数据的时候可能需要用到Id,这里Uri对象提供了一个getPathSegmengts()
方法,以"/"把uri内容分割放到字符串数组中。这样可以通过取数组[1]的位置得到id
最后还要在AndroidManifest.xml文件里注册内容提供器
<provider
android:name="com.xx.xx.provider"
android:authorities="com.xx.xxx.xx"
android.exported="true"
</provider>
2.去操作上面那个provider提供的数据
使用
getContentResolver()
来进行各种操作。
总结
ContentProvider的存在使得应用程序之间数据共享与数据共享时的安全得以共存,不必担心数据泄露。
不知不觉写到了第七章,有过想放弃的时候,但是想想还是善始善终,不忘初心。记录下来学习的点点滴滴。嗯,就是这样。