分类目录归档:四大组件之ContentProvider

四大组件之ContentProvider 第6节 ContentProvider的监听

更新时间 修改意见
2016-08-02 陈敏

第6节 ContentProvider的监听

ContentProvider中存储的数据内容发生变化时,是可以被关注了这些消息的查询者监听到的。

6.1 调用者监听的方法

  1. 继承ContentObserver,创建监听器类,

  2. 注册对指定Uri的监听函数,一旦该Uri指向的内容发生改变,将通知到MyObserver

  3. 当程序退出或者不需要再监听Uri的变化时,要主动取消对Uri的监听,

6.2 ContentProvider的配合

ContentProvider里,每当特定Uri上的数据发生变化,要触发对调用者的通知。通知使用ContentResolvernotifyChange()方法触发,


/**************************************************************************/
* 版权声明
* 本教程只在CSDN安豆网发布,其他网站出现本教程均属侵权。
/
**************************************************************************/

四大组件之ContentProvider 第5节 ContentProvider的使用权限

更新时间 修改意见
2016-08-02 陈敏

第5节 ContentProvider的使用权限

ContentProvider可以被其他应用使用(就像一个公共网站,可以被任何人访问);也可以被设置成只被自己所在的应用使用(就像一个内部网站,只能在公司内部访问)。

这只需要在应用的AndroidManifest.xml文件中,给ContentProvider设置上android:exported属性,

  1. android:exported属性设置成true:可被其他应用使用;
  2. android:exported属性设置成false:只能被自己所在的应用使用;

在对其他应用开放ContentProvider的时候,也可以设置上访问权限,只对部分应用开放使用的权限。

5.1 ContentProvider设置权限

  1. AndroidManifest.xml文件中,对要设置权限的ContentProvider设置上android:permission属性,该属性值可以任意指定一个字符串。通常使用程序的包名作为其中的一部分,这样可以避免和其他应用中的权限声明冲突。例如"com.anddle.provideraccess

  2. AndroidManifest.xml文件中,与同级的位置,对外声明前面使用的标签,表示这个应用发布了一个叫做com.anddle.provideraccess的权限,

    其中android:name属性的值,就是标签中设置的android:permission的值。

5.2 使用带权限的ContentProvider

假如应用B要使用应用A中带权限的ContentProvider,需要在应用B的AndroidManifest.xml中加入权限的使用,

其中,标签中设置的android:name的值,就是应用A中对外声明的那个provider的权限值。

5.3 进一步的权限设置

应用A的ContentProvider还可以将访问的权限进一步细化,分成允许读取和允许写入两种。

ContentProvider设置了读取的权限,那么其他组件想读取到该ContentProvider的内容时,就必须声明使用的权限。

ContentProvider设置了写入的权限,那么其他组件想写入该ContentProvider的内容时,就必须声明使用的权限。

  1. 声明“读取”权限,

    发布“读取”权限,

  2. 声明“写入”权限,

    发布“写入”权限,

需要注意的是,android:writePermissionandroid:readPermission权限的优先级比android:permission的优先级高,只要设置了高优先级的,那么其他应用要使用高优先级的功能,就要声明高优先级的权限。

例如,一个ContentProvider同时设置了android:readPermissionandroid:permission权限,第三方应用如果只请求了android:permission权限,是没有办法进行读取操作的。


/**************************************************************************/
* 版权声明
* 本教程只在CSDN安豆网发布,其他网站出现本教程均属侵权。
/
**************************************************************************/

四大组件之ContentProvider 第4节 ContentProvider的数据存储

更新时间 修改意见
2016-08-02 陈敏

第4节 ContentProvider的数据存储

ContentProvider的数据存储经常使用SQL实现,当然也可以采用别的存储机制。

假设这个ContentProvider需要这样一个数据表:

_id name price
1 book0 15
2 book1 13
3 book2 18

4.1 SQL实现数据存储

4.1.1 创建数据库

Android SDK提供了SQLiteOpenHelper来方便开发者使用SQL数据库。

  1. 继承SQLiteOpenHelper,创建我们的帮助类,

  2. 在构造函数中,创建数据库,指定数据库的名字和版本号,

  3. onCreate()函数中,根据前面的表格设计,创建SQL数据表,

  4. 当数据表的结构发生变化时,需要对原来数据表进行升级。这里只是简单的删除以前存在的表格,再重新创建一个表格。在实际的商用软件中,要考虑到数据库表格的变化,把以前老数据表中的数据,逐一转存到新的数据表当中。[注:sqlite不支持简单的drop column]

4.1.2 为ContentProvider添加SQL支持

修改MyContentProvider的增删改查函数,使用数据库实现对数据的操作。

  1. onCreate(),创建SQL帮助类,

  2. insert(),插入数据,

  3. delete(),删除数据,

  4. update(),更新数据,

  5. query(),查询数据,

SQLiteOpenHelper可以直接使用ContentProvider传入的SQL命令,方便开发者灵活的操作数据。

  1. SQLiteOpenHelpergetReadableDatabase()获取读取数据库的能力;
  2. SQLiteOpenHelpergetWritableDatabase()获取写入数据库的能力。

4.2 其他方式的数据存储

除了SQL,还可以使用别的方式存储数据,例如文本文件,甚至链表。

对于不使用SQL的实现方式,query()函数要返回Cursor对象,那么可以使用MatrixCursor,例如,


/**************************************************************************/
* 版权声明
* 本教程只在CSDN安豆网发布,其他网站出现本教程均属侵权。
/
**************************************************************************/

四大组件之ContentProvider 第3节 自定义ContentProvider

更新时间 修改意见
2016-08-02 陈敏

第3节 自定义ContentProvider

自定义一个ContentProvider,需要

  1. 继承ContentProvider类重新创建一个类,并实现其中的一些方法;
  2. 在应用的AndroidManifest.xml文件中,声明这个新添加的组件;

但在这之前,我们要来设计一下外部访问它采用的地址。

3.1 地址设计

Urischeme字段是固定的,使用content:

authority定义成程序的包名com.anddle.mycontentprovider

path就像是网站内部的分类,依据网站的逻辑进行划分。
假设我们的ContentProvider提供书籍book和文件file两种内容的查询操作。而每种类型都可以进行单一数据的操作和多条数据的操作。

例如,

  • 操作所有书的信息:content://com.anddle.mycontentprovider/books;
  • 操作某本特定书的信息:content://com.anddle.mycontentprovider/books/8
  • 操作所有文件的信息:content://com.anddle.mycontentprovider/files
  • 操作某个特定文件的信息:content://com.anddle.mycontentprovider/files/3

所以,在对这些地址代表的对象进行增删改查的时候,就需要分析出它们针对的对象。

3.2 创建ContentProvider子类

  1. 继承ContentProvider类,会要求我们实现getType() insert() delete() update() query() onCreate()等接口,

  2. 定义提供给其他组件使用的“网络地址”URI,这里我们把它们定义成content://com.anddle.mycontentprovider/books content://com.anddle.mycontentprovider/files

  3. 定义解析地址的匹配器,

    UriMatcher可以对传入的字符串进行匹配检测,如果匹配成功,会返回一个对应的值,例如,

    type就等于FILES的值2。利用这个方法,我们就可以区分出Uri访问ContentProvider时,到底希望操作什么样的数据。

    创建匹配器的时候,加入sUriMatcher.addURI("content://com.anddle.mycontentprovider","files/#", FILE);这种带有”#”的关键字段,表示如下这种匹配方式,即匹配任何数字

    创建匹配器的时候,加入sUriMatcher.addURI("content://com.anddle.mycontentprovider","files/*", FILE);这种带有”#”的关键字段,表示如下这种匹配方式,即匹配任何字符

  4. 在回调函数中,根据Uri,做对应的操作,

    这里就要实现对数据增删改查的真正操作。

    ContentProvider中,可以使用很多方式对数据进行保存、修改,例如SQL数据库。不过我们暂时不去实现,把它放到下一个章节专门介绍。

    其他delete() update() query()实现的函数做类似处理。

  5. 对于getType(), 需要为每一种类型的Uri返回一种数据类型-MIME type,告诉调用者,当前这种Uri可以处理什么类型的数据。

    它的格式型如type\subtype,有很多知名的MIME type类型,例如application/pdf image/jpeg等等,可以在网上查找到公开的MIME type类型有哪些。也可以自定义自己应用支持的特殊MIME type类型。

    这里我们就返回一个空值,

至此,一个ContentProvider的就完成了。不过它现在还没有添加上真正可以存储数据的功能。

3.3 声明ContentProvider

千万不要忘记,在应用的AndroidManifest.xml文件中,声明新添加的ContentProvider

这里的android:authorities属性值,就要填写定义MyContentProvider时,代码中的那个,

android:exported属性如何设置成true,说明这个ContentProvider可以被其他应用使用(就像一个公共网站,可以被任何人访问),如果设置成false,说明它只能被自己所在的应用使用(就像一个内部网站,只能在公司内部访问)。

3.4 使用自定义ContentProvider

无论是使用应用自己的ContentProvider还是使用其他应用提供的,它们的使用方式都和使用系统提供的ContentProvider一样,

  1. 添加一条数据数据:通过ContentResolver获取访问ContentProvider的入口,使用ContentValues添加要插入的数据;

    通常会返回指向刚成功插入的这条数据的Uri(内容就如content://com.anddle.mycontentprovider/books/8)。

  2. 删除一条数据:通过ContentResolver获取访问ContentProvider的入口,使用Uri删除指定的数据;

  3. 修改一条数据:通过ContentResolver获取访问ContentProvider的入口,使用Uri更新指定的数据,要修改的数据放在ContentValues当中;

  4. 查询某一类的数据(或者特定某条数据),

注意,在删改查的操作中,还会使用诸如where sortOrder keywords searcgKey这样的参数,它们是辅助ContentProvider查询特定数据时用的。

虽然Uri已经能定位到某条具体的数据了,但是大部分的ContentProvider都是通过SQL数据库来实现的真正存储,因此,在设计这些接口的时候就保留了SQL语言的一些用法,让使用者也能像直接操作SQL数据库那样灵活方便的使用ContentProvider

假如ContentProvider不用SQL实现数据存储功能,而采用别的存储机制,那么这些额外的参数就可以派上别的用场或者完全用不着。


/**************************************************************************/
* 版权声明
* 本教程只在CSDN安豆网发布,其他网站出现本教程均属侵权。
/
**************************************************************************/

四大组件之ContentProvider 第2节 使用ContentProvider

更新时间 修改意见
2016-08-02 陈敏

第2节 使用ContentProvider

安卓系统上,提供了很多系统级的ContentProvider,我们可以直接使用。例如,

  1. Media Provider:用来查询磁盘上多媒体文件;
  2. Contacts Provider:用来查询联系人信息;
  3. Calendar Provider:用来提供日历相关信息的查询;
  4. Bookmark Provider:用来提供书签信息的查询;

它们的用法大同小异,只要使用它们对应的Uri地址就可以进行增删改查的操作了。

这里我们就用Media Provider来讲解。

2.1 MediaProvider

Media Provider作为系统级别的应用程序在系统上运行,专门负责收集多媒体文件(音频、视频、文件)相关的信息。

Media Provider在开机启动后,会在后台“监听”磁盘上文件的变化,特定情况下,会自动更新媒体文件的信息,例如磁盘上是否增加了媒体文件,是否被删除了媒体文件,有的媒体文件名称是否发生了修改等等。

所以当任何应用想获取这类文件相关的信息时,就可以向Media Provider发起查询的请求。Media Provider帮我们完成了媒体文件信息的收集。因此,当我们要查询磁盘上的多媒体信息时,就不用自己去遍历磁盘上的文件进行收集和整理了。

2.2 Media Provider查询视频文件

  1. 确定向Media Provider发出查询请求的地址-uri,我们要查询的视频文件都是存放在外部存储地址上的,就使用指向外部存储的uri;

  2. 确定要请求的视频文件信息。我们需要查询视频的标题、创建时间,还需要播放它时使用的文件所在地址。这些信息在Media Provider中都对应着查询它们使用的字段名称;

  3. 确定查询的条件。这个条件参数的写法就和SQL数据库语言的语法一样。这里我们不打算讲SQL语法,需要各位自己去学习了;设置成空,表示查询所有数据项,

  4. 设定查询结果的排序方式,使用默认的排序方式就可以了,

  5. 获取ContentResolver对象,让它使用前面的参数向Media Provider发起查询请求;查询的结果存放在Cursor--游标当中;

  6. 遍历Cursor,得到它指向的每一条查询到的信息;当Cursor指向某条数据的时候,我们就获取它携带的每个字段的值;

  7. Cursor使用完了之后要把它关闭掉,


整理一下前面的各个步骤,获取外部存储上的视频资源,方式如下,

最后一点千万不要忘记,因为视频文件存放在外部存储器中,所以要在应用的AndroidManifest.xml文件中,添加读取外部存储器的权限,


/**************************************************************************/
* 版权声明
* 本教程只在CSDN安豆网发布,其他网站出现本教程均属侵权。
/
**************************************************************************/

四大组件之ContentProvider 第1节 ContentProvider介绍

更新时间 修改意见
2016-08-02 陈敏

第1节 ContentProvider介绍

ContentProvider是安卓系统的四大组件之一,可以向其他组件提供数据访问的能力。它就像是一个网站,其他组件(或者其他应用)可以通过“网址”访问它,获取需要的信息。因此它可以作为不同应用之间共享数据的一种方式。

1.1 基础功能

我们操作一个应用的数据,无外乎四种操作方式,

  • 增:添加新的数据;
  • 删:删除已有的数据;
  • 改:修改已经的数据;
  • 查:查询已有的数据;

所以一个ContentProvider要对外提供这四种最基础的功能至少一种。

1.2 操作的对象

对数据的操作范围无外乎,

  • 单条数据的操作:每一次操作增加一条数据,删除一条数据,修改一条数据,查询特定一条数据的详细内容;
  • 多条数据的操作:每一次操作增加多条数据,删除多条数据,修改多条数据,查询符合某个特征的多条数据;

例如,我们可能会向书架上“一次放一本书”-单条增,“一次取下一本书”-单条删,“一次问书架上有多少书”-多条查。

因此,仿照网站地址的设计方式,我们可以用如下的“网络地址”来表达我们希望进行的操作是针对单一一条数据还是同时多条数据:

  • xxx.xxx.xxx/items/1:针对单一一条数据,最后的数字代表特定一本书的编号(也可以使用书的名字来代替);
  • xxx.xxx.xxx/items:针对多条数据;

“网站”只要看到以上的格式就知道,要操作的是一条数据还是多条数据了。

每个ContentProvider就是一个“网站”,每个网站都有自己的“网址”。安卓系统为这个“网址”设计了如下的结构,

  1. scheme:固定为“content”,相当于一个网址的“http”;
  2. authority:由开发者自己确定,通常把它写成这个ContentProvider的包名,例如“com.anddle.mycontentprovider”,它就相当于网址的地址“www.google.com”;
  3. path:根据查询内容的逻辑,由开发者自己决定,通常要分成多条数据和单一数据两类;

典型的例子就像这样,

这里面,
scheme:“content”
authority:“com.anddle.mycontentprovider”
path:“items”或者“items/1”

只要定义好了前面两种原则,外界(其他组件或者其他应用)就可以获取到ContentProvider中的内容了。


/**************************************************************************/
* 版权声明
* 本教程只在CSDN安豆网发布,其他网站出现本教程均属侵权。
/
**************************************************************************/