分享

内容提供者ContentProvider的使用详解

 jiffes 2019-01-31

1.什么是ContentProvider

首先,ContentProvider(内容提供者)是android中的四大组件之一,但是在一般的开发中,可能使用的比较少。
ContentProvider为不同的软件之间数据共享,提供统一的接口。也就是说,如果我们想让其他的应用使用我们自己程序内的数据,就可以使用ContentProvider定义一个对外开放的接口,从而使得其他的应用可以使用咱们应用的文件、数据库内存储的信息。当然,自己开发的应用需要给其他应用共享信息的需求可能比较少见,但是在Android系统中,很多系统自带应用,比如联系人信息,图片库,音频库等应用,为了对其他应用暴露数据,所以就使用了ContentProvider机制。所以,我们还是要学习ContentProvider的基本使用,在遇到获取联系人信息,图片库,音频库等需求的时候,才能更好的实现功能

2.如何定义一个ContentProvider

Android系统为了让我们更好的对外暴露数据,提供了统一的接口,所以定义了抽象类ContentProvider,因此,如果我们想对外提供数据,我们需要继承ContentProvider,并且实现下面的这几个方法:

onCreate()
当我们的provider初始化时被调用,我们应该在这个方法里面完成部分初始化操作
query() 查询方法,用于给调用者返回数据
insert() 插入操作,用于让外部应用插入数据到内容提供者中
update() 更新操作,用于更新内容提供者的数据
delete() 用于删除数据
getType 返回内容提供者的MIME Type

上面这些方法,当我们继承自ContentProvider的时候,eclipse会自动的给我们添加,但是这并不代表我们每个方法都需要自定义实现。如果我们只希望给其他应用提供数据,而不允许其他应用修改我们的数据,那么我们只需要实现onCreate(),getType()和query()这三个方法就可以了,其他的三个方法我们可以根据业务需求,实现或者是不实现。

因为一般使用ContentProvider向外部暴露数据库的信息,因此,本篇将以使用ContentProvider向其他应用暴露数据库信息为例,讲解ContentProvider的基本使用。

Android中SQLite数据库的创建和使用,本篇不再介绍,不清楚的请看这篇文章

假设读者已经学会了SQLite数据库的使用,并且已经建立好了数据库,下面我们开始写我们的ContentProvider。
因为注释解析的比较详细,所以就不过多解释了
  1. /**
  2. * 内容提供者
  3. *
  4. * @author ZhaoKaiQiang
  5. * @time 2014年6月6日
  6. */
  7. public class StudentProvider extends ContentProvider {
  8. // 数据库操作类,用于获取SQLiteDatabase
  9. private MyDbOpenHelper dbHelper;
  10. private static final int STUDENT = 1;
  11. private static final int STUDENTS = 2;
  12. // UriMatcher类是一个很重要的类,因为我们需要根据传入的uri,来判断执行相对应的操作
  13. private static final UriMatcher MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
  14. // 静态代码块用于初始化MATCHER需要匹配的uri
  15. static {
  16. // MATCHER.addURI(主机名(用于唯一标示一个ContentProvider,这个需要和清单文件中的authorities属性相同),路径(可以用来表示我们要操作的数据,路径的构建应根据业务而定),返回值(用于匹配uri的时候,作为匹配的返回值));
  17. MATCHER.addURI("com.example.mydbdemo.StudentProvider", "student", STUDENTS);
  18. MATCHER.addURI("com.example.mydbdemo.StudentProvider", "student/#", STUDENT);
  19. }
  20. // 进行数据的初始化操作
  21. @Override
  22. public boolean onCreate() {
  23. dbHelper = new MyDbOpenHelper(getContext());
  24. return false;
  25. }
  26. // 查询
  27. // 如果uri为 content://com.example.mydbdemo.StudentProvider/student
  28. // 则代表查询所有的student表内的数据
  29. // 如果uri为 content://com.example.mydbdemo.StudentProvider/student/6
  30. // 则代表查询student表内id=6的数据
  31. @Override
  32. public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
  33. SQLiteDatabase db = dbHelper.getReadableDatabase();
  34. //判断传入的uri到底匹配哪一个,从而实现不同的业务需求
  35. switch (MATCHER.match(uri)) {
  36. //查询全部的学生信息
  37. case STUDENTS:
  38. //db.query(表明, 要查询的列(是一个String数组), where条件, where条件中的参数, groupBy, having, sortOrder);
  39. return db.query("student", projection, selection, selectionArgs, null, null, sortOrder);
  40. //查询某一个id对应的学生的信息
  41. case STUDENT:
  42. //取出我们要查询的数据的id
  43. long id = ContentUris.parseId(uri);
  44. String where = "id=" + id;
  45. //将selection查询信息拼接到我们的where条件中
  46. if (selection != null && !"".equals(selection)) {
  47. where = selection + " and " + where;
  48. }
  49. return db.query("student", projection, where, selectionArgs, null, null, sortOrder);
  50. //如uri不匹配,抛出不合法参数的异常
  51. default:
  52. throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
  53. }
  54. }
  55. // 插入
  56. @Override
  57. public Uri insert(Uri uri, ContentValues values) {
  58. SQLiteDatabase db = dbHelper.getWritableDatabase();
  59. switch (MATCHER.match(uri)) {
  60. case STUDENTS:
  61. long id = db.insert("student", "name", values);
  62. return ContentUris.withAppendedId(uri, id);
  63. default:
  64. throw new IllegalArgumentException("Uri不匹配");
  65. }
  66. }
  67. //删除数据
  68. @Override
  69. public int delete(Uri uri, String selection, String[] selectionArgs) {
  70. SQLiteDatabase db = dbHelper.getWritableDatabase();
  71. int count = 0;
  72. switch (MATCHER.match(uri)) {
  73. case STUDENTS:
  74. count = db.delete("student", selection, selectionArgs);
  75. return count;
  76. case STUDENT:
  77. long id = ContentUris.parseId(uri);
  78. String where = "id=" + id;
  79. if (selection != null && !"".equals(selection)) {
  80. where = selection + " and " + where;
  81. }
  82. count = db.delete("student", where, selectionArgs);
  83. return count;
  84. default:
  85. throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
  86. }
  87. }
  88. //更新数据
  89. @Override
  90. public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
  91. SQLiteDatabase db = dbHelper.getWritableDatabase();
  92. int count = 0;
  93. switch (MATCHER.match(uri)) {
  94. case STUDENTS:
  95. count = db.update("student", values, selection, selectionArgs);
  96. return count;
  97. case STUDENT:
  98. long id = ContentUris.parseId(uri);
  99. String where = "id=" + id;
  100. if (selection != null && !"".equals(selection)) {
  101. where = selection + " and " + where;
  102. }
  103. count = db.update("student", values, where, selectionArgs);
  104. return count;
  105. default:
  106. throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
  107. }
  108. }
  109. // 用于获取MIME Type
  110. @Override
  111. public String getType(Uri uri) {
  112. switch (MATCHER.match(uri)) {
  113. case STUDENT:
  114. return "vnd.android.cursor.item/student";
  115. case STUDENTS:
  116. return "vnd.android.cursor.dir/student";
  117. default:
  118. throw new IllegalArgumentException("Unkwon Uri:" + uri.toString());
  119. }
  120. }
  121. }

我们在定义好我们的ContentProvider之后,因为ContentProvider数据四大组件之一,因此我们还需要在AndroidManifest清单文件中进行注册才能使用,下面是注册信息

  1. <!-- 不要忘记exported这个属性,如果不加,可能会导致外部程序访问失败,错误信息为权限拒绝 -->
  2. <!-- authorities这个属性就是我们在ContentProvider中使用的addURI方法时的第一个参数的取值 -->
  3. <provider
  4. android:name="com.example.mydbdemo.StudentProvider"
  5. android:exported="true"
  6. android:authorities="com.example.mydbdemo.StudentProvider" >
  7. </provider>

注意,provider的声明和activity一样,都是在application节点进行声明的。

至此,我们就完成了我们自己的ContentProvider的生命,其他的应用现在就可以使用我们往外部暴露的数据信息了。

3.外部应用如何使用我们的ContentProvider

我们已经定义好了我们自己的ContentProvider,那么外部应用如何调用呢?
下面,我将新建一个测试单元工程,完成对ContentProvider的各个方法的测试

添加方法测试
  1. //使用ContentProvider添加数据的测试
  2. public void testadd() throws Throwable {
  3. //获取ContentResolver对象,完成对ContentProvider的调用
  4. ContentResolver contentResolver = this.getContext().getContentResolver();
  5. //构建我们的uir,这个uri
  6. Uri insertUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student");
  7. ContentValues values = new ContentValues();
  8. values.put("name", "zhaokaikai");
  9. values.put("age", 91);
  10. values.put("school", "bbbb");
  11. //返回值为我们刚插入进入的数据的uri地址
  12. Uri uri = contentResolver.insert(insertUri, values);
  13. Log.i(TAG, uri.toString());
  14. }

删除方法测试

  1. //使用ContentProvider删除数据的测试
  2. public void testDelete() throws Throwable {
  3. ContentResolver contentResolver = this.getContext().getContentResolver();
  4. //删除id为6的学生信息
  5. Uri deleteUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student/6");
  6. contentResolver.delete(deleteUri, null, null);
  7. }


修改方法测试
  1. //使用ContentProvider更新数据的测试
  2. public void testUpdate() throws Throwable {
  3. ContentResolver contentResolver = this.getContext().getContentResolver();
  4. //更新id = 6 的学生信息
  5. Uri updateUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student/6");
  6. ContentValues values = new ContentValues();
  7. values.put("name", "testUp");
  8. values.put("age", "101");
  9. values.put("school", "ccccc");
  10. contentResolver.update(updateUri, values, null, null);
  11. }

  1. //使用ContentProvider查询数据的测试
  2. public void testFind() throws Throwable {
  3. ContentResolver contentResolver = this.getContext().getContentResolver();
  4. //这个uri用于查询所有的数据,若查询某个id的数据,则构建下面的uri
  5. //Uri selectUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student/要查询的id");
  6. Uri selectUri = Uri.parse("content://com.example.mydbdemo.StudentProvider/student");
  7. Cursor cursor = contentResolver.query(selectUri, null, null, null, "id desc");
  8. while (cursor.moveToNext()) {
  9. int id = cursor.getInt(cursor.getColumnIndex("id"));
  10. String name = cursor.getString(cursor.getColumnIndex("name"));
  11. int age = cursor.getInt(cursor.getColumnIndex("age"));
  12. String school = cursor.getString(cursor.getColumnIndex("school"));
  13. Log.i(TAG, "id=" + id + ",name=" + name + ",age=" + age +",school="+school);
  14. }
  15. }

上面的方法都经过了单元测试。

好了,至此,我们就使用ContentProvider实现了在第三方应用中对我们应用的数据库进行增删改查等操作

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多