第1节 ContentProvider介绍
ContentProvider
是安卓系统的四大组件之一,可以向其他组件提供数据访问的能力。它就像是一个网站,其他组件(或者其他应用)可以通过“网址”访问它,获取需要的信息。因此它可以作为不同应用之间共享数据的一种方式。
1.1 基础功能
我们操作一个应用的数据,无外乎四种操作方式,
- 增:添加新的数据;
- 删:删除已有的数据;
- 改:修改已经的数据;
- 查:查询已有的数据;
所以一个ContentProvider
要对外提供这四种最基础的功能至少一种。
1.2 操作的对象
对数据的操作范围无外乎,
- 单条数据的操作:每一次操作增加一条数据,删除一条数据,修改一条数据,查询特定一条数据的详细内容;
- 多条数据的操作:每一次操作增加多条数据,删除多条数据,修改多条数据,查询符合某个特征的多条数据;
例如,我们可能会向书架上“一次放一本书”-单条增,“一次取下一本书”-单条删,“一次问书架上有多少书”-多条查。
因此,仿照网站地址的设计方式,我们可以用如下的“网络地址”来表达我们希望进行的操作是针对单一一条数据还是同时多条数据:
- xxx.xxx.xxx/items/1:针对单一一条数据,最后的数字代表特定一本书的编号(也可以使用书的名字来代替);
- xxx.xxx.xxx/items:针对多条数据;
“网站”只要看到以上的格式就知道,要操作的是一条数据还是多条数据了。
每个ContentProvider
就是一个“网站”,每个网站都有自己的“网址”。安卓系统为这个“网址”设计了如下的结构,
scheme://authority/path
scheme
:固定为“content”,相当于一个网址的“http”;authority
:由开发者自己确定,通常把它写成这个ContentProvider
的包名,例如“com.anddle.mycontentprovider”,它就相当于网址的地址“www.google.com”;path
:根据查询内容的逻辑,由开发者自己决定,通常要分成多条数据和单一数据两类;
典型的例子就像这样,
多条数据
content://com.anddle.mycontentprovider/items
单一数据
content://com.anddle.mycontentprovider/items/1
这里面,
scheme:“content”
authority:“com.anddle.mycontentprovider”
path:“items”或者“items/1”
只要定义好了前面两种原则,外界(其他组件或者其他应用)就可以获取到ContentProvider
中的内容了。
第2节 使用ContentProvider
安卓系统上,提供了很多系统级的ContentProvider
,我们可以直接使用。例如,
Media Provider
:用来查询磁盘上多媒体文件;Contacts Provider
:用来查询联系人信息;Calendar Provider
:用来提供日历相关信息的查询;Bookmark Provider
:用来提供书签信息的查询;
它们的用法大同小异,只要使用它们对应的Uri地址就可以进行增删改查的操作了。
这里我们就用Media Provider
来讲解。
2.1 MediaProvider
Media Provider
作为系统级别的应用程序在系统上运行,专门负责收集多媒体文件(音频、视频、文件)相关的信息。
Media Provider
在开机启动后,会在后台“监听”磁盘上文件的变化,特定情况下,会自动更新多媒体文件的信息,例如磁盘上是否增加了媒体文件,是否被删除了媒体文件,有的媒体文件名称是否发生了修改等等。
所以当任何应用想获取这类文件相关的信息时,就可以向Media Provider
发起查询的请求。Media Provider
帮我们完成了视频文件信息的收集,因此,当我们要查询磁盘上的多媒体信息时,就不用自己去遍历磁盘上的文件进行视频文件的收集和整理了。
2.2 Media Provider查询视频文件
- 确定向
Media Provider
发出查询请求的地址-uri,我们要查询的视频文件都是存放在外部存储地址上的,就使用指向外部存储的uri;//uri就是:content://media/external/video/media" Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
- 确定要请求的视频文件信息。我们需要查询视频的标题、创建时间,还需要播放它时使用的文件所在地址。这些信息在
Media Provider
中都对应着查询它们使用的字段名称;String[] searchKey = new String[] { MediaStore.Video.Media.TITLE, -->对应文件的标题 MediaStore.Images.Media.DATA, -->对应文件的存放位置 MediaStore.Images.Media.DATE_ADDED -->对应文件的创建时间 };
- 确定查询的条件。这个条件参数的写法就和
SQL
数据库语言的语法一样。这里我们不打算讲SQL
语法,需要各位自己去学习了;设置成空,表示查询所有数据项,String where = null;
- 设定查询结果的排序方式,使用默认的排序方式就可以了,
String sortOrder = MediaStore.Video.Media.DEFAULT_SORT_ORDER;
- 获取ContentResolver对象,让它使用前面的参数向
Media Provider
发起查询请求;查询的结果存放在Cursor
--指标当中;ContentResolver resolver = getContentResolver(); Cursor cursor = resolver.query( uri, searchKey, where, null, sortOrder);
- 遍历
Cursor
,得到它指向的每一条查询到的信息;当Cursor
指向某条数据的时候,我们就获取它携带的每个字段的值;while(cursor.moveToNext()) { String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)); String name = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.TITLE)); String createdTime = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_ADDED)); ...... }
Cursor
使用完了之后要把它关闭掉,cursor.close();
整理一下前面的各个步骤,获取外部存储上的视频资源,方式如下,
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] searchKey = new String[] {
MediaStore.Video.Media.TITLE,
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.DATE_ADDED
};
String [] keywords = null;
String where = null;
String sortOrder = MediaStore.Video.Media.DEFAULT_SORT_ORDER;
ContentResolver resolver = getContentResolver();
Cursor cursor = resolver.query(
uri,
searchKey,
where,
keywords,
sortOrder);
if(cursor != null)
{
while(cursor.moveToNext())
{
String path = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA));
String name = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.TITLE));
String createdTime = cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_ADDED));
......
}
cursor.close();
}
最后一点千万不要忘记,因为视频文件存放在外部存储器中,所以要在应用的AndroidManifest.xml
文件中,添加读取外部存储器的权限,
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.anddle.anddleplayer">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
......
</manifest>