Pro Android学习笔记(一)——ContentProvider(上)

时间:2022-12-26 13:13:58

ContentProvider,Android四大组件之一。他是系统提供的一种抽象的数据服务。Android Developer对她的概述为:

Pro Android学习笔记(一)——ContentProvider(上)

  大概意思就是说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可以查看所连接设备

Pro Android学习笔记(一)——ContentProvider(上)Pro Android学习笔记(一)——ContentProvider(上)

在这里我使用的是Genymotion的模拟器,号称最快的模拟器。

然后键入adb shell就可以进入android设备的shell。

Pro Android学习笔记(一)——ContentProvider(上)Pro Android学习笔记(一)——ContentProvider(上)

在这里我们就能进行一些linux命令的操作,但是,但是,对linux的命令支持并不全面,很多都没有。可以使用“ls /system/bin”命令查看可以执行哪些命令。

Pro Android学习笔记(一)——ContentProvider(上)

Pro Android学习笔记(一)——ContentProvider(上)

太多就不截了。

OK,通过命令"ls -l /data/data/"我们能够查看/data/data/目录下的文件,这里面就保存了应用程序的数据文件,包括数据库。

来看下联系人示例,联系人保存在"/data/data/com.android.providers.cantacts/"下,通过命令“ls /data/data/com.android.providers.contacts/”查看该文件下的数据

Pro Android学习笔记(一)——ContentProvider(上)

Pro Android学习笔记(一)——ContentProvider(上)

可以看到其中都保存了些什么,我们只关心database,所以执行“ls /data/data/com.android.providers.contacts/databases”

Pro Android学习笔记(一)——ContentProvider(上)

Pro Android学习笔记(一)——ContentProvider(上)

里面以数据库的格式保存了我们的联系人。

我们可以使用sqlite3对数据库进行操作,执行“sqlite3  /data/data/com.android.proviers.contacts/databases/contacts.db”

Pro Android学习笔记(一)——ContentProvider(上)

Pro Android学习笔记(一)——ContentProvider(上)

注意此处,由shell环境进入到了sqlite的操作环境。

执行".help"可以查看可执行命令了,在此不多说了。我们通过命令行查看数据库总是不方便,我们可以导出文件到本地电脑,然后通过图形化工具查看。首先,回退到windows的cmd环境底下,执行命令“adb pull /data/data/com.android.providers/contacts/contacts.db D:/”,这里我导出到了我本地磁盘D盘。

然后就可以用数据库工具查看了,Pro Android中使用的是Sqliteman。

记录一些常用数据库语言:

select * from table1; 
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 ....
    以上是我们查看Android设备中的ContentProvider,因为ContentProvider主要使用数据库存储,所以我们基本是查看的数据库。

(二)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" 
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://com.your-company.SomeProvider/”就是一个URI,有没有一种很眼熟的感觉,对,他就像HTTP一样,因为ContentProvider才用了REST和Web服务的抽象机制。
uri的格式如下:
content://<authority-name>/<path-segment1>/<path-segment2>/etc… 
例子:content://com.google.provider.NotePad/notes/23
    其中,notes就是path-segment,而23,就是我们要访问资源的ID。

    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 return
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
    Where条件语句的用法:ContentProvider提供了两种方式来传递where字句

1、通过URI

Activity somActivity
// ..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
2、通过string字句与一组可替换的字符串数据参数的组合

public final Cursor managedQuery(Uri uri,
String[] projection,
String selection,
String[] seleciontArgs,
String sortOrder)