ContentProvider (内容提供者)是一种共享型组件,可以为系统内应用于与应用之间提供访问接口。

ContentProvide要想正常工作需要三个关键点:

  • ContentProvider:对外提供数据的访问接口。
  • Uri:ContentProvider的唯一标识,外界可根据其访问对应的ContentProvider。
  • ContentResolver

比如,当应用A想把自己数据暴露出来让别的应用也可以操作的话,就可以在应用A内部创建一个ContentProvider实现相关方法并添加URI,然后在其他应用中(应用B)就可以通过ContentResolver和URI来访问应用A中的ContentProvider了。

很多人都会觉得ContentProvider很难理解,因为很多书上在介绍ContentProvider是后上来就用很复杂的方式来讲解,还结合什么数据库、xml等等之类操作,搞得看起来很复杂,让很多的初学者望而却步,其实我们完全不必害怕。你可以把ContentProvider看做是一个网站,在生活中你想访问一个网站就必须要有一个URL地址,而这里的URI就好比这个URL地址,然后就可以用ContentResolver拿着这个这个URI地址去访问了。

一、创建自己的ContentProvider

  • 创建ContentProvider。

创建一个自己的ContentProvider也很简单,同四大组件中其他的组件类似,首先继承系统ContentProvider来创建一个类,并实现相关方法:

  1. public class UserInfoProvider extends ContentProvider {
  2. static final String TAG = UserInfoProvider.class.getSimpleName();
  3. @Override
  4. public boolean onCreate() {
  5. Log.i(TAG, "onCreate: ");
  6. return false;
  7. }
  8. @Nullable
  9. @Override
  10. public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
  11. Log.i(TAG, "query: ");
  12. return null;
  13. }
  14. @Nullable
  15. @Override
  16. public String getType(@NonNull Uri uri) {
  17. Log.i(TAG, "getType: ");
  18. return null;
  19. }
  20. @Nullable
  21. @Override
  22. public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
  23. Log.i(TAG, "insert: ");
  24. return null;
  25. }
  26. @Override
  27. public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
  28. Log.i(TAG, "delete: ");
  29. return 0;
  30. }
  31. @Override
  32. public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
  33. Log.i(TAG, "update: ");
  34. return 0;
  35. }
  36. }

然后再 AndroidMainfest.xml 中注册并添加 authorities,这个authorities就是传入到URI中用的,注意要将exported设为true这样外界才能访问到。

  1. <provider
  2. android:name=".contentprovides.UserInfoProvider"
  3. android:authorities="cn.codingblock.androidadvancestudy.contentprovides.UserInfoProvider"
  4. android:exported="true" />

一个基本的ContentProvider创建好了,接下来要做的就是使用ContentResolver来访问它了。

  • 解析Uri

解析Uri使用Uri.parse()来解析,传入对应的参数,参数格式为:

content://authorities/ 对应于上面的UserInfoProvider来说,一个URI为:

  1. Uri uri = Uri.parse("content://cn.codingblock.androidadvancestudy.contentprovides.UserInfoProvider/");
  • 通过Context.getContentResolver()获取ContentResolver对象。
  1. ContentResolver contentResolver = getContentResolver();

我们另外新建一个工程,暂且叫做TestApp吧,在这个新的工程里面添加一个Activity,在Activity中使用ContentResolver,通过URI来访问上面的(不同应用中)ContentProvider。

  1. public class UserInfoResolverActivity extends AppCompatActivity implements View.OnClickListener {
  2. private final static String TAG = UserInfoResolverActivity.class.getSimpleName();
  3. private ContentResolver contentResolver;
  4. private Uri uri = Uri.parse("content://cn.codingblock.androidadvancestudy.contentprovides.UserInfoProvider/");
  5. Button btn_insert;
  6. Button btn_query;
  7. Button btn_update;
  8. Button btn_delete;
  9. @Override
  10. protected void onCreate(Bundle savedInstanceState) {
  11. super.onCreate(savedInstanceState);
  12. setContentView(R.layout.activity_user_info_resolver);
  13. // 获取ContentResolver对象
  14. contentResolver = getContentResolver();
  15. btn_insert = (Button) findViewById(R.id.btn_insert);
  16. btn_query = (Button) findViewById(R.id.btn_query);
  17. btn_update = (Button) findViewById(R.id.btn_update);
  18. btn_delete = (Button) findViewById(R.id.btn_delete);
  19. btn_insert.setOnClickListener(this);
  20. btn_query.setOnClickListener(this);
  21. btn_update.setOnClickListener(this);
  22. btn_delete.setOnClickListener(this);
  23. }
  24. @Override
  25. public void onClick(View view) {
  26. switch (view.getId()) {
  27. case R.id.btn_insert:
  28. insert();
  29. break;
  30. case R.id.btn_query:
  31. query();
  32. break;
  33. case R.id.btn_update:
  34. update();
  35. break;
  36. case R.id.btn_delete:
  37. delete();
  38. break;
  39. }
  40. }
  41. public void insert() {
  42. Uri tempUri = contentResolver.insert(uri, values);
  43. Log.i(TAG, "insert: tempUri = " + tempUri);
  44. }
  45. public void query() {
  46. Cursor cursor = contentResolver.query(uri, null, "where", null, null);
  47. Log.i(TAG, "query: cursor = " + cursor);
  48. }
  49. public void update() {
  50. int n = contentResolver.update(uri, values, "where", null);
  51. Log.i(TAG, "update: n = " + n);
  52. }
  53. public void delete() {
  54. int n = contentResolver.delete(uri, "where", null);
  55. Log.i(TAG, "delete: n = " + n);
  56. }
  57. }

需要注意一点是,这个UserInfoProvider和UserInfoResolverActivity并没有在同一个应用中,UserInfoProvider在AndroidAdvanceStudy这个应用里面,他的进程名是:cn.codingblock.androidadvancestudy。UserInfoResolverActivity在TestApp应用里面,进程名是:cn.codingblock.testapp。

在testApp点击以上的增、查、改、删按钮,log如下:

  1. 12-12 15:06:26.846 28104-28118/cn.codingblock.androidadvancestudy I/UserInfoProvider: insert:
  2. 12-12 15:06:28.070 28104-28118/cn.codingblock.androidadvancestudy I/UserInfoProvider: query:
  3. 12-12 15:06:29.733 28104-28118/cn.codingblock.androidadvancestudy I/UserInfoProvider: update:
  4. 12-12 15:06:30.376 28104-28118/cn.codingblock.androidadvancestudy I/UserInfoProvider: delete:

看,我们是在TestApp应用中做的相关操作,果然可以调用AndroidAdvanceStudy里面的UserInfoProvider。

ContenProvider就是这么简单,当然 ContentProvider 的功能远不止如此,我们也可以结合数据库或者SharePreference等实现更加复杂的对外数据操作。

二、调用系统的ContentProvider

除了我们自己创建ContentProvider,Android系统也给我们提供了丰富的ContentProvider接口,这里就以操作系统的联系人为例来说明一下怎使用系统提供的ContentProvider接口。

  • ContactsContract.Contacts.CONTENT_URI:联系人Uri。
  • ContactsContract.CommonDataKinds.Phone.CONTENT_URI:联系人电话号码Uri。

1、查询系统联系人

通过系统联系人的Uri获取系统联系人及手机号码:

  1. public void query() {
  2. showContact = "";
  3. // 获取联系人的Cursor集合
  4. Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
  5. while (cursor.moveToNext()) {
  6. // 获取联系人id
  7. String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
  8. // 获取联系人姓名
  9. String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
  10. // 获取当前联系人id下的所有电话号码
  11. Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
  12. null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=" + id, null, null);
  13. showContact += "--id="+ id + " | name=" + name + "--\n";
  14. Log.i(TAG, "onCreate: ------id="+ id + " | name=" + name + "------");
  15. while (phones.moveToNext()) {
  16. String phone = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
  17. showContact += "phone = " + phone + "\n";
  18. Log.i(TAG, "onCreate: phone = " + phone);
  19. }
  20. phones.close();
  21. }
  22. cursor.close();
  23. tv_show.setText(showContact);
  24. }

查询后log如下:

  1. 12-13 17:19:49.490 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=1 | name=张飞------
  2. 12-13 17:19:49.490 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 151 1511 1511
  3. 12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=2 | name=关羽------
  4. 12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 153 6969 3869
  5. 12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 135 6497 8664
  6. 12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 155 5555 5555
  7. 12-13 17:19:49.499 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 133 3333 3333
  8. 12-13 17:19:49.508 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=3 | name=刘备------
  9. 12-13 17:19:49.508 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 156 9637 5648
  10. 12-13 17:19:49.508 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 153 7564 8643
  11. 12-13 17:19:49.520 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=14 | name=吕布------
  12. 12-13 17:19:49.520 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15678909087
  13. 12-13 17:19:49.529 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=20 | name=孙权------
  14. 12-13 17:19:49.529 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15366669999
  15. 12-13 17:19:49.538 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=21 | name=曹操------
  16. 12-13 17:19:49.538 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15699788966
  17. 12-13 17:19:49.547 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=22 | name=马超------
  18. 12-13 17:19:49.547 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15366999966

2、添加系统联系人:

  1. public void insert() {
  2. String name = et_name.getText().toString();
  3. String phone = et_phone.getText().toString();
  4. if (TextUtils.isEmpty(name) || TextUtils.isEmpty(phone)) {
  5. Toast.makeText(getApplicationContext(), "不能为空", Toast.LENGTH_LONG).show();
  6. return;
  7. }
  8. ContentValues values = new ContentValues();
  9. // 往插入一个空值以便获取id
  10. Uri rawContactUri = getContentResolver().insert(ContactsContract.RawContacts.CONTENT_URI, values);
  11. long rawContactId = ContentUris.parseId(rawContactUri);
  12. // ------插入联系人姓名------
  13. // 设置id
  14. values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
  15. // 设置内容类型
  16. values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
  17. // 设置名字
  18. values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, name);
  19. // 插入姓名
  20. getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
  21. values.clear();
  22. // ------插入联系人电话------
  23. values.put(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
  24. values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
  25. values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);
  26. values.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
  27. getContentResolver().insert(ContactsContract.Data.CONTENT_URI, values);
  28. Toast.makeText(getApplicationContext(), "添加成功", Toast.LENGTH_LONG).show();
  29. query();
  30. }

在输入框中输入联系人姓名(诸葛亮)及电话号码(13696969696),然后点击添加按钮,log如下:

  1. 12-13 17:23:37.577 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=1 | name=张飞------
  2. 12-13 17:23:37.577 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 151 1511 1511
  3. 12-13 17:23:37.589 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=2 | name=关羽------
  4. 12-13 17:23:37.590 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 153 6969 3869
  5. 12-13 17:23:37.590 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 135 6497 8664
  6. 12-13 17:23:37.590 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 155 5555 5555
  7. 12-13 17:23:37.590 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 133 3333 3333
  8. 12-13 17:23:37.603 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=3 | name=刘备------
  9. 12-13 17:23:37.603 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 156 9637 5648
  10. 12-13 17:23:37.603 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 153 7564 8643
  11. 12-13 17:23:37.616 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=14 | name=吕布------
  12. 12-13 17:23:37.617 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15678909087
  13. 12-13 17:23:37.630 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=20 | name=孙权------
  14. 12-13 17:23:37.630 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15366669999
  15. 12-13 17:23:37.657 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=21 | name=曹操------
  16. 12-13 17:23:37.657 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15699788966
  17. 12-13 17:23:37.671 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=22 | name=马超------
  18. 12-13 17:23:37.671 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 15366999966
  19. 12-13 17:23:37.712 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: ------id=23 | name=诸葛亮------
  20. 12-13 17:23:37.712 14978-14978/cn.codingblock.androidadvancestudy I/ContactProviderActivity: onCreate: phone = 13696969696

可以看到,诸葛亮和电话号码已经被成功添加进去了。

当然,除了以上几个Uri,系统的ContentProvider接口还有很多很多,就不一一举例了,用到时可以查询官方API。


最后想说的是,本系列文章为博主对Android知识进行再次梳理,查缺补漏的学习过程,一方面是对自己遗忘的东西加以复习重新掌握,另一方面相信在重新学习的过程中定会有巨大的新收获,如果你也有跟我同样的想法,不妨关注我一起学习,互相探讨,共同进步!

参考文献:

  • 《Android开发艺术探索》
  • 《Android开发进阶从小工到专家》

Android查缺补漏--ContentProvider的使用的更多相关文章

  1. Android查缺补漏(IPC篇)-- Bundle、文件共享、ContentProvider、Messenger四种进程间通讯介绍

    本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8387752.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...

  2. Android查缺补漏(IPC篇)-- 进程间通讯基础知识热身

    本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8479282.html 在Android中进程间通信是比较难的一部分,同时又非常 ...

  3. Android查缺补漏(IPC篇)-- 款进程通讯之AIDL详解

    本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...

  4. Android查缺补漏(IPC篇)-- 进程间通讯之Socket简介及示例

    本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8425736.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...

  5. Android查缺补漏(IPC篇)-- 进程间通讯之AIDL详解

    本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8436529.html 进程间通讯篇系列文章目录: Android查缺补漏(IP ...

  6. Android查缺补漏(View篇)--自定义 View 的基本流程

    View是Android很重要的一部分,常用的View有Button.TextView.EditView.ListView.GridView.各种layout等等,开发者通过对这些View的各种组合以 ...

  7. Android查缺补漏(View篇)--事件分发机制源码分析

    在上一篇博文中分析了事件分发的流程及规则,本篇会从源码的角度更进一步理解事件分发机制的原理,如果对事件分发规则还不太清楚的童鞋,建议先看一下上一篇博文 <Android查缺补漏(View篇)-- ...

  8. Android查缺补漏(线程篇)-- IntentService的源码浅析

    本文作者:CodingBlock 文章链接:http://www.cnblogs.com/codingblock/p/8975114.html 在Android中有两个比较容易弄混的概念,Servic ...

  9. Android查缺补漏--Activity生命周期和启动模式

    一.生命周期 onCreate():启动Activity时,首次创建Activity时回调. onRestart():再次启动Activity时回调. onStart():首次启动Activity时在 ...

随机推荐

  1. [转载] 快速理解Kafka分布式消息队列框架

    转载自http://blog.csdn.net/xiaolang85/article/details/18048631 ==是什么 == 简单的说,Kafka是由Linkedin开发的一个分布式的消息 ...

  2. [转载] Java集合---HashMap源码剖析

    转载自http://www.cnblogs.com/ITtangtang/p/3948406.html 一.HashMap概述 HashMap基于哈希表的 Map 接口的实现.此实现提供所有可选的映射 ...

  3. MySQL GTIDs(global transaction identifiers)

    1.如何定义和生成GTIDs 唯一性:在所有主从库都是唯一的,由二元组构成 每个事务和GTIDs之间都有1:1映射 GTID = source_id:transaction_id source_id标 ...

  4. 深入学习JS执行--单线程的JS

    一.介绍 随着js不断学习,你可能会慢慢的好奇,用了这么久的js,却不知道这js在浏览器怎么被执行的,很尴尬.所以,我查阅很多资料来总结JS的执行过程,也分享出来,和大家一起学习. 本篇主要讲单线程的 ...

  5. 安装VisualSVN Server时候,端口号冲突

    今天在本机安装VisualSVN Server 时,发现https默认端口号:443被占用了, 于是到cmd下面执行 netstat -ano命令发现是pid:4276的进程在试用, 打开任务管理里一 ...

  6. SurfaceView 及相关概念

    ============================================================= SurfaceView=========================== ...

  7. 正确释放Vector的内存

    http://blog.jobbole.com/37700/ 今天在看微博的时候, 有人提出了一个对于Vector内存泄露的疑问( Link). 博主采用 Vector存储一些数据,但是发现在执行 c ...

  8. 2017上半年技术文章集合【Android】—184篇文章分类汇总

    地址: http://blog.csdn.net/androidstarjack/article/details/77923753 声明 | 本文是于亚豪 原创 终端研发部 前言: 2017年已经过大 ...

  9. 初识NumPy库-基本操作

    ndarray(N-dimensional array)对象是整个numpy库的基础. 它有以下特点: 同质:数组元素的类型和大小相同 定量:数组元素数量是确定的 一.创建简单的数组: np.arra ...

  10. HDU4508--完全背包

    湫湫系列故事--减肥记I Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Tot ...