ContentProvider
android
平台提供了Content Provider
使一个应用程序的指定数据集提供给其他应用程序。这些数据可以存储在文件系统中、在一个SQLite
数据库、或以任何其他合理的方式,其他应用可以通过ContentResolver
类(见ContentProviderAccessApp
例子)从该内容提供者中获取或存入数据.(相当于在应用外包了一层壳),只有需要在多个应用程序间共享数据是才需要内容提供者。例如,通讯录数据被多个应用程序使用,且必须存储在一个内容提供者中
它的好处:统一数据访问方式。
android系统自带的内容提供者(顶级的表示数据库名,非顶级的都是表名)这些内容提供者在SDK文档的android.provider Java包中都有介绍。见:http://developer.android.com/reference/android/provider/package-summary.html
├────Browser
├────CallLog
├────Contacts
│ ├────Groups
│ ├────People
│ ├────Phones
│ └────Photos
├────Images
│ └────Thumbnails
├────MediaStore
│ ├────Albums
│ ├────Artists
│ ├────Audio
│ ├────Genres
│ └────Playlists
├────Settings
└────Video
CallLog:地址和接收到的电话信息
Contact.People.Phones:存储电话号码
Setting.System:系统设置和偏好设置
使用Content Provider对外共享数据的步骤
继承ContentProvider类并根据需求重写以下方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52//处理初始化操作
public boolean onCreate();
/**
* 插入数据到内容提供者(允许其他应用向你的应用中插入数据时重写)
* @param uri
* @param initialValues 插入的数据
* @return
*/
public Uri insert(Uri uri, ContentValues initialValues);
/**
* 从内容提供者中删除数据(允许其他应用删除你应用的数据时重写)
* @param uri
* @param selection 条件语句
* @param selectionArgs 参数
* @return
*/
public int delete(Uri uri, String selection, String[] selectionArgs);
/**
* 更新内容提供者已存在的数据(允许其他应用更新你应用的数据时重写)
* @param uri
* @param values 更新的数据
* @param selection 条件语句
* @param selectionArgs 参数
* @return
*/
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs);
/**
* 返回数据给调用者(允许其他应用从你的应用中获取数据时重写)
* @param uri
* @param projection 列名
* @param selection 条件语句
* @param selectionArgs 参数
* @param sortOrder 排序
* @return
*/
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) ;
/**
* 用于返回当前Uri所代表数据的MIME类型
* 如果操作的数据为集合类型(多条数据),那么返回的类型字符串应该为vnd.android.cursor.dir/开头
* 例如要得到所有person记录的Uri为content://com.bravestarr.provider.personprovider/person,
* 那么返回的MIME类型字符串应该为"vnd.android.cursor.dir/person"
* 如果操作的数据为单一数据,那么返回的类型字符串应该为vnd.android.cursor.item/开头
* 例如要得到id为10的person记录的Uri为content://com.bravestarr.provider.personprovider/person/10,
* 那么返回的MIME类型字符串应该为"vnd.android.cursor.item/person"
* @param uri
*/
public String getType(Uri uri)这些方法中的Uri参数,得到后需要进行解析然后做对应处理,Uri表示要操作的数据,包含两部分信息:
需要操作的
contentprovider
对
contentprovider
中的什么数据进行操作,一个Uri格式:结构头://authorities(域名)/路径(要操作的数据,根据业务而定)
content://com.bravestarr.provider.personprovider/person/10
说明:
contentprovider
的结构头已经由android
规定为content://authorities
用于唯一标识这个contentprovider
程序,外部调用者可以根据这个找到他路径表示我们要操作的数据,路径的构建根据业务而定.路径格式如下:要操作
person
表行号为10
的记录,可以这样构建/person/10
要操作
person
表的所有记录,可以这样构建/person
在
AndroidManifest.xml
中使用<provider>
对ContentProvider
进行配置注册(内容提供者注册它自己就像网站注册域名),ContentProvider
采用authoritie
(原意授权,可理解为域名)作为唯一标识,方便其他应用能找到1
2
3
4
5
6
7
8
9<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<!-- authorities属性命名建议:公司名.provider.SomeProvider-->
<provider
android:name=".PersonProvider"
ndroid:authorities="com.bravestarr.provider.personprovider"/>
...
</application>
ContentProvider
管理对结构化数据集的访问。它们封装数据,并提供用于定义数据安全性的机制。 内容提供程序是连接一个进程中的数据与另一个进程中运行的代码的标准界面。
ContentProvider
无法被用户感知,对于一个 ContentProvider
组件来说,它的内部需要实现增删该查这四种操作,它的内部维持着一份数据集合,这个数据集合既可以是数据库实现,也可以是其他任何类型,如 List
和 Map
,内部的 insert
、delete
、update
、query
方法需要处理好线程同步,因为这几个方法是在 Binder
线程池中被调用的。
ContentProvider
通过 Binder
向其他组件乃至其他应用提供数据。当 ContentProvider
所在的进程启动时,ContentProvider
会同时启动并发布到 AMS 中,需要注意的是,这个时候 ContentProvider
的 onCreate
要先于 Application
的 onCreate
而执行。
基本使用
1 | // Queries the user dictionary and returns results |
1 | public class Installer extends ContentProvider { |
- 自己创建一个
ContentProvider
或往已存在的Provider
中写数据,供其他应用访问。 - 访问
ContentProvider
时,可通过Activity
或Context
的方法getContentResolver
来访问 - 每个
ContentProvider
都有个唯一的URI来识别 ContentProvider
的生命周期不可人为控制,在进程创建时创建,随进程消亡而消亡。
四大基本组件的总结
四大组件的注册
四大基本组件都需要注册才能使用,每个
Activity
、service
、Content Provider
内容提供者都需要在AndroidManifest
文件中进行配置。AndroidManifest
文件中未进行声明的activity
、服务
以及内容提供者
将不为系统所见,从而也就不可用,而BroadcastReceive
广播接收者的注册分静态注册(在AndroidManifest
文件中进行配置)和通过代码动态创建并以调用Context.registerReceiver()
的方式注册至系统。需要注意的是在AndroidManifest
文件中进行配置的广播接收者会随系统的启动而一直处于活跃状态,只要接收到感兴趣的广播就会触发(即使程序未运行)AndroidManifest
文件中进行注册格式如下:<activity>
元素的name
属性指定了实现了这个activity
的Activity
的子类。icon
和label
属性指向了包含展示给用户的此activity
的图标和标签的资源文件。<service>
元素用于声明服务<receiver>
元素用于声明广播接收器<provider>
元素用于声明内容提供者
四大组件的激活
容提供者的激活:当接收到
ContentResolver
发出的请求后,内容提供者被激活。而其它三种组件──activity
、服务
和广播接收器
被一种叫做intent
的异步消息所激活Activity
的激活通过传递一个Intent
对象至Context.startActivity()
或Activity.startActivityForResult()
以载入(或指定新工作给)一个activity
。相应的activity
可以通过调用getIntent()
方法来查看激活它的intent
。如果它期望它所启动的那个activity
返回一个结果,它会以调用startActivityForResult()
来取代startActivity()
。比如说,如果它启动了另外一个Activity
以使用户挑选一张照片,它也许想知道哪张照片被选中了。结果将会被封装在一个Intent
对象中,并传递给发出调用的activity
的onActivityResult()
方法。服务
的激活可以通过传递一个Intent
对象至Context.startService()
或Context.bindService()
前者Android
调用服务的onStart()
方法并将Intent
对象传递给它,后者Android
调用服务的onBind()
方法将这个Intent
对象传递给它发送广播可以通过传递一个
Intent
对象至给Context.sendBroadcast()
、Context.sendOrderedBroadcast()
或Context.sendStickyBroadcast()
Android
会调用所有对此广播有兴趣的广播接收器的onReceive()
方法,将intent
传递给它们
四大组件的关闭
内容提供者仅在响应
ContentResolver
提出请求的时候激活。而一个广播接收器仅在响应广播信息的时候激活。所以,没有必要去显式的关闭这些组件。
Activity
关闭:可以通过调用它的finish()
方法来关闭一个activity
服务关闭:对于通过
startService()
方法启动的服务要调用Context.stopService()
方法关闭服务,使用bindService()
方法启动的服务要调用Contex.unbindService()
方法关闭服务