当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据。虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:

    采用文件方式对外共享数据,需要进行文件操作读写数据;
    采用SharedPreferences共享数据,需要使用SharedPreferences API读写数据。而使用ContentProvider共享数据的好处是统一了数据访问方式。


    1:schema,用来说明一个ContentProvider控制这些数据。 “content://“
    2:主机名或授权(Authority),它定义了是哪个ContentProvider提供这些数据。
    3:path路径,URI下的某一个Item。
    4:ID, 通常定义Uri时使用”#”号占位符代替, 使用时替换成对应的数字

    “content://com.itheima.provider/person/#” #表示数据id(#代表任意数字)
    “content://com.itheima.provider/person/来匹配任意文本

    ContentProvider共享数据
    onCreate 其它应用第一次访问时被调。
    insert 外部应用使用此方法添加数据。
    delete 外部应用使用此方法删除数据。
    update 外部应用使用此方法更新数据。
    query 外部应用使用此方法查询数据。
    getType 主要用于匹配数据类型(例如:接收系统广播时传递的数据类型),返回当前Uri所代表数据的MIME类型。如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/自定义类型。数据属于非集合类型数据,应该返回vnd.android.cursor.item/自定义类型。
    UriMatcher 用于匹配Uri
    ContentUris 获取和添加Uri信息

    UriMatcher类使用介绍
    UriMatcher类用于匹配Uri,它的用法如下:

    首先第一步把你需要匹配Uri路径全部给注册上,如下:

    1. //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码
    2. UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    3. //如果match()方法匹配content://cn.itcast.provider.personprovider/person路径,返回匹配码为1
    4. sMatcher.addURI(“cn.itcast.provider.personprovider”, person”, 1);//添加需要匹配uri,如果匹配就会返回匹配码
    5. //如果match()方法匹配content://cn.itcast.provider.personprovider/person/230路径,返回匹配码为2
    6. sMatcher.addURI(“cn.itcast.provider.personprovider”, person/#”, 2);//#号为通配符
    7. switch (sMatcher.match(Uri.parse("content://cn.itcast.provider.personprovider/person/10"))) {
    8. case 1
    9. break;
    10. case 2
    11. break;
    12. default://不匹配
    13. break;
    14. }

    注册完需要匹配的Uri后,就可以使用sMatcher.match(uri)方法对输入的Uri进行匹配,如果匹配就返回匹配码,匹配码是调用addURI()方法传入的第三个参数,假设匹配

    1. content://cn.itcast.provider.personprovider/person路径,返回的匹配码为1
    2. ContentUris类用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
    3. withAppendedId(uri, id)用于为路径加上ID部分:
    4. Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")
    5. Uri resultUri = ContentUris.withAppendedId(uri, 10);
    6. //生成后的Uri为:content://cn.itcast.provider.personprovider/person/10
    7. parseId(uri)方法用于从路径中获取ID部分:
    8. Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person/10")
    9. long personid = ContentUris.parseId(uri);//获取的结果为:10
    10. 另外Uri类中还有一个静态方法withAppendedPath(baseUri, pathSegment)也可以在某个路径上继续添加路径:
    11. Uri uri = Uri.parse("content://cn.itcast.provider.personprovider/person")
    12. Uri resultUri = Uri.withAppendedPath(uri, update”);
    13. // 生成后的Uri为: content://cn.itcast.provider.personprovider/person/update

    使用ContentObserver监听ContentProvider中数据的变化

    如果ContentProvider的访问者需要知道ContentProvider中的数据发生了变化,可以在ContentProvider 发生数据变化时调用getContentResolver().notifyChange(uri, null)来通知注册在此URI上的访问者,例子如下:

    1. public class PersonContentProvider extends ContentProvider {
    2. public Uri insert(Uri uri, ContentValues values) {
    3. db.insert("person", "personid", values);
    4. getContext().getContentResolver().notifyChange(uri, null);
    5. }
    6. }

    如果ContentProvider的访问者需要得到数据变化通知,必须使用ContentObserver对数据(数据采用uri描述)进行监听,当监听到数据变化通知时,系统就会调用ContentObserver的onChange()方法:

    1. getContentResolver().registerContentObserver(Uri.parse("content://cn.itcast.providers.personprovider/person"),
    2. true, new PersonObserver(new Handler()));
    3. public class PersonObserver extends ContentObserver{
    4. public PersonObserver(Handler handler) {
    5. super(handler);
    6. }
    7. public void onChange(booleanselfChange) {
    8. //此处可以进行相应的业务处理
    9. }
    10. }

    定义一个ContentProvider内容提供者

    1. public class PersonContentProvider extends ContentProvider {
    2. private static final String AUTHORITY = "com.test.sqlitedemo.providers.PersonContentProvider";
    3. private static final int PRESON_INSERT_CODE = 0; // 操作person表添加的操作的uri匹配码
    4. private static final int PERSON_DELETE_CODE = 1;
    5. private static final int PERSON_UPDATE_CODE = 2;
    6. private static final int PERSON_QUERY_ALL_CODE = 3;
    7. private static final int PERSON_QUERY_ITEM_CODE = 4;
    8. private static UriMatcher uriMatcher;
    9. private PersonSQLiteOpenHelper mOpenHelper; // person表的数据库帮助对象
    10. static {
    11. uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    12. // 添加一些uri(分机号)
    13. // content://com.test.sqlitedemo.providers.PersonContentProvider/person/insert
    14. uriMatcher.addURI(AUTHORITY, "person/insert", PRESON_INSERT_CODE);
    15. // content://com.test.sqlitedemo.providers.PersonContentProvider/person/delete
    16. uriMatcher.addURI(AUTHORITY, "person/delete", PERSON_DELETE_CODE);
    17. // content://com.test.sqlitedemo.providers.PersonContentProvider/person/update
    18. uriMatcher.addURI(AUTHORITY, "person/update", PERSON_UPDATE_CODE);
    19. // content://com.test.sqlitedemo.providers.PersonContentProvider/person/queryAll
    20. uriMatcher.addURI(AUTHORITY, "person/queryAll", PERSON_QUERY_ALL_CODE);
    21. // content://com.test.sqlitedemo.providers.PersonContentProvider/person/query/#
    22. uriMatcher.addURI(AUTHORITY, "person/query/#", PERSON_QUERY_ITEM_CODE);
    23. }
    24. @Override
    25. public boolean onCreate() {
    26. mOpenHelper = new PersonSQLiteOpenHelper(getContext());
    27. return true;
    28. }
    29. @Override
    30. public Cursor query(Uri uri, String[] projection, String selection,
    31. String[] selectionArgs, String sortOrder) {
    32. SQLiteDatabase db = mOpenHelper.getReadableDatabase();
    33. switch (uriMatcher.match(uri)) {
    34. case PERSON_QUERY_ALL_CODE: // 查询所有人的uri
    35. if(db.isOpen()) {
    36. Cursor cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder);
    37. return cursor;
    38. // db.close(); 返回cursor结果集时, 不可以关闭数据库
    39. }
    40. break;
    41. case PERSON_QUERY_ITEM_CODE: // 查询的是单条数据, uri末尾出有一个id
    42. if(db.isOpen()) {
    43. long id = ContentUris.parseId(uri);
    44. Cursor cursor = db.query("person", projection, "_id = ?", new String[]{id + ""}, null, null, sortOrder);
    45. return cursor;
    46. }
    47. break;
    48. default:
    49. throw new IllegalArgumentException("uri不匹配: " + uri);
    50. }
    51. return null;
    52. }
    53. @Override
    54. public String getType(Uri uri) {
    55. switch (uriMatcher.match(uri)) {
    56. case PERSON_QUERY_ALL_CODE: // 返回多条的MIME-type
    57. return "vnd.android.cursor.dir/person";
    58. case PERSON_QUERY_ITEM_CODE: // 返回单条的MIME-TYPE
    59. return "vnd.android.cursor.item/person";
    60. default:
    61. break;
    62. }
    63. return null;
    64. }
    65. @Override
    66. public Uri insert(Uri uri, ContentValues values) {
    67. switch (uriMatcher.match(uri)) {
    68. case PRESON_INSERT_CODE: // 添加人到person表中
    69. SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    70. if(db.isOpen()) {
    71. long id = db.insert("person", null, values);
    72. db.close();
    73. return ContentUris.withAppendedId(uri, id);
    74. }
    75. break;
    76. default:
    77. throw new IllegalArgumentException("uri不匹配: " + uri);
    78. }
    79. return null;
    80. }
    81. @Override
    82. public int delete(Uri uri, String selection, String[] selectionArgs) {
    83. switch (uriMatcher.match(uri)) {
    84. case PERSON_DELETE_CODE: // 在person表中删除数据的操作
    85. SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    86. if(db.isOpen()) {
    87. int count = db.delete("person", selection, selectionArgs);
    88. db.close();
    89. return count;
    90. }
    91. break;
    92. default:
    93. throw new IllegalArgumentException("uri不匹配: " + uri);
    94. }
    95. return 0;
    96. }
    97. @Override
    98. public int update(Uri uri, ContentValues values, String selection,
    99. String[] selectionArgs) {
    100. switch (uriMatcher.match(uri)) {
    101. case PERSON_UPDATE_CODE: // 更新person表的操作
    102. SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    103. if(db.isOpen()) {
    104. int count = db.update("person", values, selection, selectionArgs);
    105. db.close();
    106. return count;
    107. }
    108. break;
    109. default:
    110. throw new IllegalArgumentException("uri不匹配: " + uri);
    111. }
    112. return 0;
    113. }
    114. }

    声明自定义的权限:

    1. <permission android:name="aa.bb.cc.read" ></permission>
    2. <permission android:name="aa.bb.cc.write" ></permission>

    在AndroidManifest.xml中声明内容提供者、
    在application标签内添加

    1. <provider
    2. android:name=".providers.PersonContentProvider"
    3. android:authorities="com.itheima28.sqlitedemo.providers.PersonContentProvider"
    4. android:readPermission="aa.bb.cc.read" //设置读取需要的权限
    5. android:writePermission="aa.bb.cc.write" > //设置写入需要的权限
    6. </provider>

    测试内容提供者:

    1. public class TextCase extends AndroidTestCase {
    2. private static final String TAG = "TextCase";
    3. public void testInsert() {
    4. Uri uri = Uri.parse("content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/insert");
    5. // 内容提供者访问对象
    6. ContentResolver resolver = getContext().getContentResolver();
    7. ContentValues values = new ContentValues();
    8. values.put("name", "fengjie");
    9. values.put("age", 90);
    10. uri = resolver.insert(uri, values);
    11. Log.i(TAG, "uri: " + uri);
    12. long id = ContentUris.parseId(uri);
    13. Log.i(TAG, "添加到: " + id);
    14. }
    15. public void testDelete() {
    16. Uri uri = Uri.parse("content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/delete");
    17. // 内容提供者访问对象
    18. ContentResolver resolver = getContext().getContentResolver();
    19. String where = "_id = ?";
    20. String[] selectionArgs = {"21"};
    21. int count = resolver.delete(uri, where, selectionArgs);
    22. Log.i(TAG, "删除行: " + count);
    23. }
    24. public void testUpdate() {
    25. Uri uri = Uri.parse("content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/update");
    26. // 内容提供者访问对象
    27. ContentResolver resolver = getContext().getContentResolver();
    28. ContentValues values = new ContentValues();
    29. values.put("name", "lisi");
    30. int count = resolver.update(uri, values, "_id = ?", new String[]{"20"});
    31. Log.i(TAG, "更新行: " + count);
    32. }
    33. public void testQueryAll() {
    34. Uri uri = Uri.parse("content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/queryAll");
    35. // 内容提供者访问对象
    36. ContentResolver resolver = getContext().getContentResolver();
    37. Cursor cursor = resolver.query(uri, new String[]{"_id", "name", "age"}, null, null, "_id desc");
    38. if(cursor != null && cursor.getCount() > 0) {
    39. int id;
    40. String name;
    41. int age;
    42. while(cursor.moveToNext()) {
    43. id = cursor.getInt(0);
    44. name = cursor.getString(1);
    45. age = cursor.getInt(2);
    46. Log.i(TAG, "id: " + id + ", name: " + name + ", age: " + age);
    47. }
    48. cursor.close();
    49. }
    50. }
    51. public void testQuerySingleItem() {
    52. Uri uri = Uri.parse("content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/query/#");
    53. // 在uri的末尾添加一个id content://com.itheima28.sqlitedemo.providers.PersonContentProvider/person/query/20
    54. uri = ContentUris.withAppendedId(uri, 20);
    55. // 内容提供者访问对象
    56. ContentResolver resolver = getContext().getContentResolver();
    57. Cursor cursor = resolver.query(uri, new String[]{"_id", "name", "age"}, null, null, null);
    58. if(cursor != null && cursor.moveToFirst()) {
    59. int id = cursor.getInt(0);
    60. String name = cursor.getString(1);
    61. int age = cursor.getInt(2);
    62. cursor.close();
    63. Log.i(TAG, "id: " + id + ", name: " + name + ", age: " + age);
    64. }
    65. }
    66. }