ContentProvider,Android四大组件之一。他是系统提供的一种抽象的数据服务。Android Developer对她的概述为:
大概意思就是说ContentProvider(内容提供者)就是为应用程序提供数据。他压缩数据并通过ContentResolver接口提供给应用程序。当我们需要在多个应用程序之间共享数据的时候,我们才考虑使用ContentProvider,否则我们可以直接使用SQLiteDataBase。当一个URI形式的请求通过ContentResolver并且通过注册的Authority请求ContentProvider的时候,ContentProvider可以把URI解释成它想要的(这一段话我也不太会翻译,有不对的地方还望斧正)。
我们看看这里面涉及到了哪些概念:
(1)ContentProvider,内容提供者。
(2)ContentResolver,用于数据操作的抽象类。
(3)URI,代表了要操作的数据,类似于HTTP URI。
(4)UriMatcher,Uri匹配器,对传递过来的URI进行分析匹配。
以后,还会涉及到
(5)ContentValue,存储键值对用于ContentResolver处理。
(6)Cursor,光标,可以想象成文本编辑器中的光标。
官方的概述还是很难理解,我们慢慢来看。
(一)查看Android内置ContentProvider
使用adb可以查看设备内部的ContentProvider。将手机(此处手机应为root之后)连接电脑或者打开模拟器,命令行打开adb。
使用adb devices可以查看所连接设备
在这里我使用的是Genymotion的模拟器,号称最快的模拟器。
然后键入adb shell就可以进入android设备的shell。
在这里我们就能进行一些linux命令的操作,但是,但是,对linux的命令支持并不全面,很多都没有。可以使用“ls /system/bin”命令查看可以执行哪些命令。
太多就不截了。
OK,通过命令"ls -l /data/data/"我们能够查看/data/data/目录下的文件,这里面就保存了应用程序的数据文件,包括数据库。
来看下联系人示例,联系人保存在"/data/data/com.android.providers.cantacts/"下,通过命令“ls /data/data/com.android.providers.contacts/”查看该文件下的数据
可以看到其中都保存了些什么,我们只关心database,所以执行“ls /data/data/com.android.providers.contacts/databases”
里面以数据库的格式保存了我们的联系人。
我们可以使用sqlite3对数据库进行操作,执行“sqlite3 /data/data/com.android.proviers.contacts/databases/contacts.db”
注意此处,由shell环境进入到了sqlite的操作环境。
执行".help"可以查看可执行命令了,在此不多说了。我们通过命令行查看数据库总是不方便,我们可以导出文件到本地电脑,然后通过图形化工具查看。首先,回退到windows的cmd环境底下,执行命令“adb pull /data/data/com.android.providers/contacts/contacts.db D:/”,这里我导出到了我本地磁盘D盘。
然后就可以用数据库工具查看了,Pro Android中使用的是Sqliteman。
记录一些常用数据库语言:
select * from table1;以上是我们查看Android设备中的ContentProvider,因为ContentProvider主要使用数据库存储,所以我们基本是查看的数据库。
select count(*) from table1;
select col1, col2 from table1;
select distinct col1 from table1;
select count(col1) from (select distinct col1 from table1);
select count(*), col1 from table1 group by col1;
select * from table1 t1, table2 t2 where t1.col1 = t2.col1;
select * from table t1 left outer join table2 t2 on t1.col1 = t2.col1 where ....
(二)ContentProvider的架构
我们在程序中使用ContentProvider的时候,首先需要注册,提供授权(Authority),vnd.android.cursor.dir/vnd.<yourcompanyname.contenttype>
在AndroidManifest文件中进行注册
<provider android:name="SomeProvider" android:authorities="com.your-company.SomeProvider" />其中,name即自定义ContentProvider的类名,可以省略包名;authorities即是为我们提供可使用的URI。 注册之后,我们就可以使用content://com.your-company.SomeProvider/来进行访问了。 在Android中,对于系统级程序我们可以使用简写的URI来进行访问,比如联系人可以直接使用contracts。然而对于我们自己的程序,则需要使用全称,否则无法使用。 以下提供了系统的contacts的注册
<provider android:name="ContactsProvider2"URI:上面提到的“content://com.your-company.SomeProvider/”就是一个URI,有没有一种很眼熟的感觉,对,他就像HTTP一样,因为ContentProvider才用了REST和Web服务的抽象机制。
android:authorities="contacts;com.android.contacts"
android:label="@string/provider_label"
android:multiprocess="false"
android:readPermission="android.permission.READ_CONTACTS"
android:writePermission="android.permission.WRITE_CONTACTS">
<path-permission
android:pathPrefix="/search_suggest_query"
android:readPermission="android.permission.GLOBAL_SEARCH"/>
<path-permission
android:pathPrefix="/search_suggest_shortcut"
android:readPermission="android.permission.GLOBAL_SEARCH"/>
<path-permission
android:pathPattern="/contacts/.*/photo"
android:readPermission="android.permission.GLOBAL_SEARCH"/>
<grant-uri-permission android:pathPattern=".*" />
</provider>
uri的格式如下:
content://<authority-name>/<path-segment1>/<path-segment2>/etc…其中,notes就是path-segment,而23,就是我们要访问资源的ID。
例子:content://com.google.provider.NotePad/notes/23
MIME Type:我们进行了一次URI请求之后就会返回数据,这类数据的类型就用MIME来表示。Android遵循了一定的约定来定义MIME类型。
对于单条记录:
vnd.android.cursor.item/vnd.<yourcompanyname.contenttype>对于记录或行的集合:
vnd.android.cursor.dir/vnd.<yourcompanyname.contenttype>
其中,vnd表示这些类型和子类型具有非标准的、供应商特定的形式。对于Android,本质上能识别项是“单个”还是“集合”项,作为程序员,我们只关心子类型,即
vnd.<yourcompanyname.contenttype>
Cursor:游标是一个行集合,在读取数据之前,我们需要使用moveToFirst(),将游标放置第一行。使用游标的时候,需要知道列类型和列名称,在访问之前,需要将列名称转化为列编号,通过游标,可以获取行计数。
以下示例演示了如何使用URI从ContentProvider获取一个游标
// An array specifying which columns to returnWhere条件语句的用法:ContentProvider提供了两种方式来传递where字句
Sting[] projection = new String[] {
Contacts._ID,
Contacts.DISPLAY_NAME_PRIMARY
};
Uri mContactsUri = ContactsContract.Contacts.CONTENT_URI;
// Best way to retrieve a query; returns a managed query
Cursor managedCursor = managedQuery(mContactsUri,
projection, // which columns to return
null, // where clause
Contacts.DISPLAY_NAME_PRIMARY + " ASC"); // Order-by clause
1、通过URI
Activity somActivity2、通过string字句与一组可替换的字符串数据参数的组合
// ..intialize someActivity
String moteUri = "content://com.google.provider.NotePad/notes/23";
Cursor managedCursor = someActivity.managedQuery(noteUri,
projection, // Which columns to return.
null, // WHERE clause
null); // Order-by clause
public final Cursor managedQuery(Uri uri,
String[] projection,
String selection,
String[] seleciontArgs,
String sortOrder)