ContentProvider是Android中提供的专门用于进程间通信,它底层也是Binder,系统已经为我们做了封装。系统预置了很多ContentProvider,比如通讯录,日程表信息等应用。访问它们都是跨进程。
ContentProvider除了onCreate之外,其他五个方法都是在Binder的线程池中执行的。
ContentProvidr主要以表格形式组织数据,还支持文件数据等。
至于ContentProvider原理,以后学习了会分析
要实现自定义ContentProvider,只需要继承ContentProvider类实现下面6个方法就可以了;

//实现的六个方法都运行在ContentProvier所在进程中
public class BookProvider extends ContentProvider {//初始化的时候调用,可以进行数据库的创建和升级等操作//返回true,表示内容提供器初始化成功,//返回false,表示初始化失败//这是唯一一个运行在主线程里面,下面5个都运行在Binder的线程池中@Overridepublic boolean onCreate() {return false;}//从内容提供器中查询数据,和Sqlite中的query差不多,除了第一个参数//uri用来确定查询那张表//projection用来确定查询那些列//selection和selectionArgs用来确定查询那些行//sortOrder用于对结果进行排序@Overridepublic Cursor query(Uri uri, String[] projection, String selection,String[] selectionArgs, String sortOrder) {return null;}//根据传入的URI来返回相应的MIME类型@Overridepublic String getType(Uri uri) {return null;}//插入数据,和Sqlite中的insert差不多,除了第一个参数//uri来请确定插入那张表//valus,存放插入的值//返回一条用于表示这表记录的URI@Overridepublic Uri insert(Uri uri, ContentValues values) {return null;}//删除数据 和Sqlite中的delete差不多,除了第一个参数//uri表示删除哪一张表//selection和selectionArgs用来确定删除那些行//被删除的行数作为返回值返回@Overridepublic int delete(Uri uri, String selection, String[] selectionArgs) {return 0;}//更新数据 和Sqlite中的update差不多,除了第一个参数//uri表示那张表//返回更新的行数@Overridepublic int update(Uri uri, ContentValues values, String selection,String[] selectionArgs) {return 0;}
}

我们知道SQLite中CRUD中方法中第一个参数是Table表名,而在ContentProvider的CRUD中使用了Uri来代替
它到底表示什么?
其实它表示的是内容URI,内容URI给内容提供者创建数据提供了唯一标识,它由两部分组成:
权限(authority)路径(path)
权限:是用于区分不同的应用程序,一般使用包名的方式来命名,比如com.shion.app包名,那么对应的权限可以命名为com.shion.app.provider.
路径:用于区分同一个应用中不同的表,通常加到权限的后面。比如一个应用中存在一张表book
那么路径可以命名为/book.
权限和路径组成一个URI,为了体现出它是URI,我们还要在前面加上协议声明content://
所以上面内容URI最标准的格式写法是:
content://com.shion.app.provider/book
得到了内容URI字符串之后,可以把它解析成 Uri对象作为参数传到ContentProvider的增删改查的方法中。

//把URI字符串解析成Uri对象
Uri uri=Uri.parse("content://com.shion.app.provider/book");了

另外要访问ContentProvider,就要使用ContentResolver类,到时看代码就知道了;
下面实现一个简单自定义ContentProvider的Demo;从ContentProvider中查询图书信息;

服务端代码
先是创建一个数据库帮助类:

public class BookDataHelper extends SQLiteOpenHelper {public BookDataHelper(Context context, String name, int version) {super(context, name, null, version);}@Overridepublic void onCreate(SQLiteDatabase db) {String sql = "create table book(_id integer primary key autoincrement,name text,author text,publisher text);";db.execSQL(sql);}@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {String sql = "drop table if exists book";db.execSQL(sql);}}

接着实现ContentProvider:

public class BookProvider extends ContentProvider {private SQLiteOpenHelper dbHelper;private static final int BOOK_DIR = 0;private static final int BOOK_ITEM = 1;private static final String AUTHORITY = "com.shion.app.provider";private static UriMatcher sUriMatcher;{sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);sUriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);sUriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);}@Overridepublic boolean onCreate() {dbHelper = new BookDataHelper(getContext(), "app.db", 1);return true;}@Overridepublic String getType(Uri uri) {switch (sUriMatcher.match(uri)) {case BOOK_DIR:return "vnd.android.cursor.dir/vnd.com.shion.app.provider.book";case BOOK_ITEM:return "vnd.android.cursor.item/vnd.com.shion.app.provider.book";default:break;}return null;}@Overridepublic synchronized Cursor query(Uri uri, String[] projection,String selection, String[] selectionArgs, String sortOrder) {SQLiteDatabase db = dbHelper.getReadableDatabase();Cursor cursor = null;switch (sUriMatcher.match(uri)) {case BOOK_DIR:cursor = db.query("book", projection, selection, selectionArgs,null, null, sortOrder);break;case BOOK_ITEM:String bookId = uri.getPathSegments().get(1);cursor = db.query("book", projection, "_id = ?",new String[] { bookId }, null, null, sortOrder);break;default:break;}return cursor;}@Overridepublic synchronized Uri insert(Uri uri, ContentValues values) {SQLiteDatabase db = dbHelper.getReadableDatabase();switch (sUriMatcher.match(uri)) {case BOOK_DIR:case BOOK_ITEM:long insertId = db.insert("book", null, values);Uri sUri = Uri.withAppendedPath(Uri.parse("content://"), AUTHORITY);return ContentUris.withAppendedId(sUri, insertId);default:break;}return null;}@Overridepublic synchronized int delete(Uri uri, String selection,String[] selectionArgs) {SQLiteDatabase db = dbHelper.getReadableDatabase();switch (sUriMatcher.match(uri)) {case BOOK_DIR:return db.delete("book", selection, selectionArgs);case BOOK_ITEM:String bookId = uri.getPathSegments().get(1);return db.delete("book", "_id = ?", new String[] { bookId });default:break;}return 0;}@Overridepublic synchronized int update(Uri uri, ContentValues values,String selection, String[] selectionArgs) {SQLiteDatabase db = dbHelper.getReadableDatabase();switch (sUriMatcher.match(uri)) {case BOOK_DIR:return db.update("book", values, selection, selectionArgs);case BOOK_ITEM:String bookId = uri.getPathSegments().get(1);return db.update("book", values, "_id = ?", new String[] { bookId });default:break;}return 0;}
}

补充一下:
1.“content://com.shion.app.provider/book”//这个内容URI表示想要访问book表
“content://com.shion.app.provider/book/1”//这个内容URI表示想要访问book表中id为1的数据
我们可以使用通配符来分别匹配他们
* : 表示匹配任意长度的的任意字符
# : 表示匹配任意长度的数字
匹配任意表可以这样写
“content://com.shion.app.provider/*”
匹配一个表中任意一行数据可以这样写
“content://com.shion.app.provider/book/#”
2. UriMatcher类可以轻松实现匹配内容URI的功能
比如下面这样就可以把权限一个自定义的常量绑定:

sUriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
sUriMatcher.addURI(AUTHORITY, "book/#", BOOK_ITEM);

当下次调用 sUriMatcher.match(uri),返回自定义的常量实现匹配,可以判断访问的是book这张表还是Book这张表中的某一行数据;

    switch (sUriMatcher.match(uri)) {case BOOK_DIR:/*Book表*/break;case BOOK_ITEM:/*Book表中某行行数据*/break;default:break;}

3.getType方法的是MIME类型返回的值是系统要求的:

3.1. 开头必须是vnd
3.2.1 如果是路径结尾后面接android.cursor.dir/
3.2.2 如果是id结尾后面接android.cursor.item/
3.3 最后是vnd..
唯一区别就是dir和item 比如下面:
内容URI为:“content://com.shion.app.provider/book”所对应的MIME类型是:
“vnd.android.cursor.dir/vnd.com.shion.app.provider.book”//表示整张表的MIME
内容URI为:“content://com.shion.app.provider/book/1”所对应的MIME类型是
“vnd.android.cursor.item/vnd.com.shion.app.provider.book”//表示某一个条记录的MIME

4.在manifest中声明provider

         <provider
            android:name="com.shion.app.BookProvider"android:authorities="com.shion.app.provider"android:exported="true" ></provider>

android:exported 是Android中的四大组件 Activity,Service,Provider,Receiver 四大组件中都会有的一个属性。
它的主要作用是:是否支持其它应用调用当前组件。
默认值:如果包含有intent-filter 默认值为true; 没有intent-filter默认值为false。


下面贴上布局文件和MainActivity中相关实现代码:

客户端
布局文件activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="10dp" ><Buttonandroid:id="@+id/btnInsertData"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="插入" /><Buttonandroid:id="@+id/btnDeleteData"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="删除" /><Buttonandroid:id="@+id/btnQueryData"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="查询" /><Buttonandroid:id="@+id/btnUpdateData"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="更改" /></LinearLayout>

java代码:

public class MainActivity extends Activity implements OnClickListener {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.btnInsertData).setOnClickListener(this);findViewById(R.id.btnDeleteData).setOnClickListener(this);findViewById(R.id.btnQueryData).setOnClickListener(this);findViewById(R.id.btnUpdateData).setOnClickListener(this);}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.btnInsertData:insert();break;case R.id.btnDeleteData:delete();break;case R.id.btnQueryData:query();break;case R.id.btnUpdateData:update();break;default:break;}}private Uri uri = Uri.parse("content://com.shion.app.provider");private void insert() {Uri inSertUri = Uri.withAppendedPath(uri, "book");ContentValues values = new ContentValues();values.put("name", "Android4编程入门经典");values.put("author", "wei-meng lee");values.put("publisher", "清华大学");getContentResolver().insert(inSertUri, values);}private void delete() {Uri deleteUri = Uri.withAppendedPath(uri, "book/1");getContentResolver().delete(deleteUri, null, null);}private void query() {Uri queryUri = Uri.withAppendedPath(uri, "book");Cursor c = getContentResolver().query(queryUri, null, null, null, null);if (c != null) {while (c.moveToNext()) {String name = c.getString(c.getColumnIndex("name"));String author = c.getString(c.getColumnIndex("author"));String publisher = c.getString(c.getColumnIndex("publisher"));Log.e("tag", "name: ===" + name);Log.e("tag", "author: ===" + author);Log.e("tag", "publisher: ===" + publisher);}}}private void update() {Uri updateUri = Uri.withAppendedPath(uri, "book");ContentValues values = new ContentValues();values.put("name", "大话数据结构");values.put("author", "程杰");values.put("publisher", "清华大学");getContentResolver().update(updateUri, values, "_id = ?",new String[] { "1" });}}

另附一些系统应用常见的Uri:

关于联系人的一些URI
管理联系人的Uri:
ContactsContract.Contacts.CONTENT_URI
管理联系人的电话的Uri:
ContactsContract.CommonDataKinds.Phone.CONTENT_URI
管理联系人的Email的Uri:
ContactsContract.CommonDataKinds.Email.CONTENT_URI
(注:Contacts有两个表,分别是rawContact和Data,
rawContact记录了用户的id和name,
id栏名称为:ContactsContract.Contacts._ID,
name名称栏为ContactContract.Contracts.DISPLAY_NAME,
电话信息表的外键id为ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
电话号码栏名称为:ContactsContract.CommonDataKinds.Phone.NUMBER.
data表中Email地址栏名称为:
ContactsContract.CommonDataKinds.Email.DATA
其外键栏为:ContactsContract.CommonDataKinds.Email.CONTACT_ID)


关于多媒体的一些URI:
存储在sd卡上的音频文件:
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI
存储在手机内部存储器上的音频文件:
MediaStore.Audio.Media.INTERNAL_CONTENT_URI
SD卡上的图片文件内容:
MediaStore.Audio.Images.EXTERNAL_CONTENT_URI
手机内部存储器上的图片:
MediaStore.Audio.Images.INTERNAL_CONTENT_URI
SD卡上的视频:
MediaStore.Audio.Video.EXTERNAL_CONTENT_URI
手机内部存储器上的视频:
MediaStore.Audio.Video.INTERNAL_CONTENT_URI
(注:图片的显示名栏:Media.DISPLAY_NAME,
图片的详细描述栏为:Media.DESCRIPTION
图片的保存位置:Media.DATA


关于短信URI:
Content://sms
发送箱中的短信URI:
Content://sms/outbox
收信箱中的短信URI:
Content://sms/sent
草稿中的短信URI:
Content://sms/draft

ContentProvider基本使用初探相关推荐

  1. ContentProvider初探

    引言 我们什么时候 会用到ContentProvider呢? 1.我们想在自己的应用中访问别的应用,或者说一些ContentProvider暴露给我们的一些数据, 比如手机联系人,短信等!我们想对这些 ...

  2. Android ContentProvider初探

    这几篇将围绕ContentProvider进行安全漏洞分析. 关于ContentProvider,网上有不少资料,但都零零碎碎,而且样例时间也较老,因此我整合了网上可靠资源,并结合自己实践给出一篇可靠 ...

  3. ContentProvider再探——Document Provider

    概述 通过ContentProvider初探相信你已经知道如何去使用系统提供的ContentProvider或者自定义ContentProvider了, 已经基本满足日常开发的需求了,有趣的是,我在官 ...

  4. android插件框架机制的选择,Android插件开发初探——基础篇

    Android插件开发初探 对于Android的插件化其实已经讨论已久了,但是市面上还没有非常靠谱成熟的插件框架供我们使用.这里我们就尝试性的对比一下Java中,我们使用插件化该是一个怎么样的流程,且 ...

  5. ContentProvider简要说明

    ContentProvider简要说明 android.content.ContentProvider 简要概述   内容提供者是 Android 应用程序的主要构建块之一,为应用程序提供内容.它们封 ...

  6. ContentProvider是如何实现数据共享的

    ContentProvider用于跨进程通讯,一个程序可以通过实现一个ContentProvider的抽象接口将自己的数据完全暴露出去,而且ContentProvider是以类似数据库中表的方式将数据 ...

  7. 2021年大数据Flink(九):Flink原理初探

    Flink原理初探 Flink角色分工 在实际生产中,Flink 都是以集群在运行,在运行的过程中包含了两类进程. JobManager: 它扮演的是集群管理者的角色,负责调度任务.协调 checkp ...

  8. 从壹开始微服务 [ DDD ] 之一 ║ D3模式设计初探 与 我的计划书

    缘起 哈喽大家周四好!又是开心的一天,时间过的真快,我们的 <从壹开始 .net core 2.1 + vue 2.5 >前后端分离系列共 34 篇已经完结了,当然以后肯定还会有更新和修改 ...

  9. 经典算法研究系列:二、Dijkstra 算法初探

    经典算法研究系列:二.Dijkstra 算法初探  July   二零一一年一月 ====================== 本文主要参考:算法导论 第二版.维基百科. 写的不好之处,还望见谅. 本 ...

最新文章

  1. arduino下载库出错_【arduino】DIY音乐播放器,arduino播放wav音乐,TRMpcm库测试及使用...
  2. python之CSV文件格式
  3. 8086汇编语言命令速查与详解
  4. 消息队列面试连环炮,你抗得住吗?
  5. mysql连接串指定编码_MYSQL创建数据库时候直接指定编码和排序规则
  6. unity fixedupdate_3D俯视角射击——用Unity还原东方弹幕(上)
  7. slf4j的简单用法以及与log4j的区别
  8. lisp eval apply_SICP远古魔法-LISP概览(1-2)
  9. 移动超级sim卡 无法下载卡_共迎未来无限可能!5G超级SIM卡亮相2019中国移动全球合作伙伴大会...
  10. spring boot + vue + element-ui全栈开发入门——windows开发环境
  11. php laravel框架失败_急急急!!!ubuntu+laravel+nginx安装完成后,请求laravel框架失败...
  12. 使用dig命令解析域名
  13. 经过几天的努力,出了 2 本保姆级编程电子书!
  14. ECharts异步数据获取
  15. java获取url后缀,以及判断是否带参数(?params=xxx)
  16. 海风的Linux开发环境介绍
  17. @Deprecated注解功能
  18. html实现微信扫一扫,JS 实现微信扫一扫功能
  19. 数字通信调制方式的误码率matlab仿真,包括OOK,PRK,FSK以及QAM
  20. 2019年涨工资指南:为什么要学AI、AI薪资水平和就业前景分析

热门文章

  1. 后缀名为jnlp的文件的打开方式
  2. IC设计中节省静态功耗和动态功耗的方法
  3. 关于PCM音频重采样思路及注意事项(频率变换和通道数变换(单通道转双通道))
  4. OLE程序开发利用(开发EXCEL) 之 一
  5. 快速了解 Robot Operating System(ROS) 机器人操作系统
  6. 数据清洗及OpenRefine工具
  7. 微信小程序 image图片组件实现宽度固定 高度自适应
  8. jQuery中的append()方法
  9. python开发微信订阅号如何申请_基于Python的微信公众平台二次开发(Python常用框架、订阅号开发、公众号开发)...
  10. 安卓四大组件之广播组件(Broadcast)