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数据库的简单实用。

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

我们在定义好我们的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. }

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

其他人的总结:{

二、Uri类简介

Uri代表了要操作的数据,Uri主要包含了两部分信息
①需要操作的ContentProvider
②对ContentProvider中的什么数据进行操作

组成部分
①scheme:ContentProvider的scheme已经由Android所规定为content://
②主机名(Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。建议为公司域名,保持唯一性
③路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定:

要操作person表中id为10的记录
content://cn.xyCompany.providers.personProvider/person/10

要操作person表中id为10的记录的name字段
content://cn.xyCompany.providers.personProvider/person/10/name

要操作person表中的所有记录
content://cn.xyCompany.providers.personProvider/person

要操作的数据不一定来自数据库,也可以是文件等他存储方式,如要操作xml文件中user节点下的name节点

content://cn.xyCompany.providers.personProvider/person/10/name

把一个字符串转换成Uri,可以使用Uri类中的parse()方法
Uri uri = Uri.parse(“content://cn.xyCompany.providers.personProvider/person”)

三、UriMatcher、ContentUris和ContentResolver简介

Uri代表了要操作的数据,所以经常需要解析Uri,并从Uri中获取数据。Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher 和ContentUris。掌握它们的使用会便于我们的开发工作。

UriMatcher

用于匹配Uri

①把需要匹配Uri路径全部给注册上

// 常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码(-1)。
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

// 若match()方法匹配content://cn.xyCompany.providers.personProvider/person路径则返回匹配码为1
uriMatcher.addURI(“content://cn.xyCompany.providers.personProvider”,”person”, 1);

// 若match()方法匹配content://cn.xyCompany.providers.personProvider/person/10路径则返回匹配码为2
uriMatcher.addURI(“content://cn.xyCompany.providers.personProvider”,”person/#”, 1);

②注册完需要匹配的Uri后,就可以使用uriMatcher.match(uri)方法对输入的Uri进行匹配

ContentUris
ContentUris是对URI的操作类,其中的withAppendedId(uri, id)用于为路径加上ID部分,parseId(uri)方法用于从路径中获取ID部分方法很实用。
Uri insertUri = Uri.parse(“content://cn.xyCompany.providers.personProvider/person” + id);等价于
Uri insertUri = ContentUris.withAppendedId(uri, id);

ContentResolver
当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查询操作时,可以使用ContentResolver
类来完成。要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。
ContentResolver使用insert、delete、update、query方法来操作数据。
}

Android基础内容提供者ContentProvider的使用详解(转)的更多相关文章

  1. Android中内容提供者ContentProvider的详解

    1.什么是ContentProvider 首先,ContentProvider(内容提供者)是android中的四大组件之一,但是在一般的开发中,可能使用的比较少. ContentProvider为不 ...

  2. [Android Pro] 内容提供者ContentProvider的基本使用

    一.ContentProvider简介 当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据.ContentProvider为存储和获取数据提 ...

  3. Android之内容提供者ContentProvider的总结

    本文包含以下知识点: ContentProvider Uri 的介绍 ContentResolver: 监听ContentProvider的数据改变 一:ContentProvider部分 Conte ...

  4. Android基础知识之String类使用详解

    原文:http://android.eoe.cn/topic/android_sdk 字符串资源为你的应用程序提供了可以选择的文本样式和格式的文本.这里有三种类型的资源可以为你的应用程序提供字符串. ...

  5. [Android Pro] 监听内容提供者ContentProvider的数据变化

    转载自:http://blog.csdn.net/woshixuye/article/details/8281385 一.提出需求 有A,B,C三个应用,B中的数据需要被共享,所以B中定义了内容提供者 ...

  6. Android开发14——监听内容提供者ContentProvider的数据变化

    一.提出需求 有A,B,C三个应用,B中的数据需要被共享,所以B中定义了内容提供者ContentProvider:A应用修改了B应用的数据,插入了一条数据.有这样一个需求,此时C应用需要得到数据被修改 ...

  7. 安卓第十四天笔记-内容提供者(ContentProvider)

    安卓第十四天笔记-内容提供者(ContentProvider) ContentProvider--内容提供者 1.ContentProvider简介 ContentProvider是不同应用程序之间进 ...

  8. Android 中内容提供者的使用

    在Android中内容提供者主要是用于不同程序之间的数据共享.内容提供器的用法一般有两种,一种是使用现有的内容提供器来读取和操作相应程序的数据,另一种是创建自己的内容提供器,供其他的程序访问. 使用现 ...

  9. Android Studio系列教程五--Gradle命令详解与导入第三方包

    Android Studio系列教程五--Gradle命令详解与导入第三方包 2015 年 01 月 05 日 DevTools 本文为个人原创,欢迎转载,但请务必在明显位置注明出处!http://s ...

随机推荐

  1. Notepad++设置运行快捷键

    python: 先按F5,之后将下面的命令保存,再设置快捷键. cmd /k c:\python27\python "$(FULL_CURRENT_PATH)" & PAU ...

  2. python类内置方法的再学习

    对于__setitem__和__getitem__方法:其入参看来是固定的(__getitem__(self, item),__setitem__(self, key, value)),我们并不需要重 ...

  3. 语法注释格式;格式化输出;input在py2和py3中的区别;数据的基本类型;运算符;

    一.Python中的注释 Python的注释是代码的评论,是让代码让人能更加清晰明确.代码的注释可分为单行注释和多行注释,单行注释用“#”,多行注释用三对单引号或者三对双引号来表示. ps:# 单行注 ...

  4. qt5--自定义控件封装

    视频教程地址:https://www.bilibili.com/video/av51766541/?p=30

  5. 《转发》特征工程——categorical特征 和 continuous特征

    from http://breezedeus.github.io/2014/11/15/breezedeus-feature-processing.html 请您移步原文观看,本文只供自己学习使用 连 ...

  6. 【leetcode】1271. Hexspeak

    题目如下: A decimal number can be converted to its Hexspeak representation by first converting it to an ...

  7. CodeForces451E Devu and Flowers

    题目链接 问题分析 没有想到母函数的做法-- 其实直接看题思路挺简单的.发现如果每种花都有无限多的话,问题变得十分简单,答案就是\(s+n-1\choose n - 1\).然后发现\(n\)只有\( ...

  8. Splay教程

    目录 前言 引入 教程 Rotate Splay 一些其他操作: 区间翻转 结语 前言 Splay是名副其实的区间小能手.它会经常出现在一些有关区间的题上.而本蒟蒻只会Treap,感到分外难受,于是就 ...

  9. A.Equivalent Prefixes(ST算法)

    Equivalent Prefixes 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 524288K,其他语言1048576K 64bit IO Format: %lld 题目描述 ...

  10. C++入门经典-例6.18-数组的动态分配,动态获得斐波那契数列

    1:有时在获得一定的信息之前,我们并不确定数组的大小.动态分配数组则可以使用变量作为数组的大小,使数组的大小符合我们的要求. 2:科普一下斐波纳契数列:斐波那契数列指的是这样一个数列 1, 1, 2, ...