android api 完整翻译之Contacts Provider (学习安卓必知的api,中英文对照)

Contacts Provider

 

电话簿(注:联系人,联络人、通信录)提供者

 

-------------------------------

 

QUICKVIEW

 

快速概览

 

* Android's repository of information about people.

 

* Android的关于人的信息的仓库。

 

* Syncs with the web.

 

* 与互联网同步。

 

* Integrates social stream data.

 

* 集成社交流数据。

 

IN THIS DOCUMENT

 

本文目录

 

* Contacts Provider Organization 电话簿提供者组织(注:结构)

* Raw contacts 原始电话簿

* Data 数据

* Contacts 电话簿

* Data From Sync Adapters 来自同步适配器的数据

* Required Permissions 必需的权限

* The User Profile 用户简介

* Contacts Provider Metadata 电话簿提供者元数据

* Contacts Provider Access 电话簿提供者访问

* Contacts Provider Sync Adapters 电话簿提供者同步适配器

* Social Stream Data 社交流(注:也可能是指社会主流)数据

* Additional Contacts Provider Features 额外的电话簿提供者特性

 

KEY CLASSES

 

关键类

 

ContactsContract.Contacts

ContactsContract.RawContacts

ContactsContract.Data

ContactsContract.StreamItems

 

RELATED SAMPLES

 

相关示例

 

Contact Manager 电话簿管理器

Sample Sync Adapter 示例同步适配器

 

SEE ALSO

 

另见

 

Content Provider Basics 内容提供者基础

 

-------------------------------

 

The Contacts Provider is a powerful and flexible Android component that manages the device's central repository of data about people. The Contacts Provider is the source of data you see in the device's contacts application, and you can also access its data in your own application and transfer data between the device and online services. The provider accommodates a wide range of data sources and tries to manage as much data as possible for each person, with the result that its organization is complex. Because of this, the provider's API includes an extensive set of contract classes and interfaces that facilitate both data retrieval and modification.

 

电话簿提供者是一种强大和灵活的Android组件,它管理设备上关于人的中心仓库。电话簿提供者是你在设备的电话簿应用程序中看到的数据的源,而你还可以在你自己的应用程序中访问它的数据并在设备和在线服务之间传输数据。提供者装载一些广泛范围的数据源并尝试为每个人管理尽可能多的数据,因此它的组织是复杂的。因为这样,提供者的API包含一个大量集合的契约类和接口,它们方便数据检索(注:retrieval还有恢复、取回的意思)和修改。

 

This guide describes the following:

 

这个指引描述以下内容:

 

* The basic provider structure. 

 

* 基本提供者结构。

 

* How to retrieve data from the provider. 

 

* 如何从提供者中取出数据。

 

* How to modify data in the provider. 

 

* 如何在修改提供者中的数据。

 

* How to write a sync adapter for synchronizing data from your server to the Contacts Provider. 

 

* 如何编写一个同步适配器以同步来自你的服务器的数据到电话簿提供者。

 

This guide assumes that you know the basics of Android content providers. To learn more about Android content providers, read the Content Provider Basics guide. The Sample Sync Adapter sample app is an example of using a sync adapter to transfer data between the Contacts Provider and a sample application hosted by Google Web Services.

 

这个指引假设你懂得Android内容提供者的基础。为了学习更多关于Android内容提供者的内容,请阅读内容提供者基础指引。示例同步适配器示例应用是一个使用同步适配器来在内容提供者和寄宿于Google Web服务下的示例应用程序之间传输数据的示例。

 

-------------------------------

 

Contacts Provider Organization

 

电话簿提供者组织(注:结构)

 

The Contacts Provider is an Android content provider component. It maintains three types of data about a person, each of which corresponds to a table offered by the provider, as illustrated in figure 1:

 

电话簿提供者是一个Android内容提供者组件。它维护关于一个人的三类数据,每类对应提供者提供的一个表,正如图1中所描绘的:

 

(图1略:

电话簿->(一对多)原始电话簿->数据(一对多)

 

Figure 1. Contacts Provider table structure.

 

图1. 电话簿提供者表结构。

 

The three tables are commonly referred to by the names of their contract classes. The classes define constants for content URIs, column names, and column values used by the tables:

 

三个表通常通过它们的契约类的名称来被引用。该类为表使用的内容URI,列名,和列值定义常量:

 

ContactsContract.Contacts table

 

ContactsContract.Contacts表

 

Rows representing different people, based on aggregations of raw contact rows.

 

代表不同的人的行,基于原始电话簿行的聚集

 

ContactsContract.RawContacts table

 

ContactsContract.RawContacts表

 

Rows containing a summary of a person's data, specific to a user account and type.

 

包含一个人的数据的摘要的行,特定于一个用户账户和类型

 

ContactsContract.Data table

 

ContactsContract.Data表

 

Rows containing the details for raw contact, such as email addresses or phone numbers.

 

包含原始电话簿的明细的行,诸如电子邮件地址或电话号码

 

The other tables represented by contract classes in ContactsContract are auxiliary tables that the Contacts Provider uses to manage its operations or support specific functions in the device's contacts or telephony applications.

 

在ContactsContract中的契约类代表的其它表是一些辅助表,电话簿提供者使用它们来管理它的操作或支持设备的电话簿或电话应用程序的一些特定功能。

 

-------------------------------

 

Raw contacts

 

原始电话簿

 

A raw contact represents a person's data coming from a single account type and account name. Because the Contacts Provider allows more than one online service as the source of data for a person, the Contacts Provider allows multiple raw contacts for the same person. Multiple raw contacts also allow a user to combine a person's data from more than one account from the same account type.

 

一个原始电话簿代表来自一个单一账户类型和账户名称的一个人的数据。因为电话簿提供者允许多于一个在线服务作为一个人的数据源,所以电话簿提供者允许同一个人的多个原始电话簿。多个原始电话簿还允许一个用户组合来自同一个账户类型多于一个账户的一个人的数据。

 

Most of the data for a raw contact isn't stored in the ContactsContract.RawContacts table. Instead, it's stored in one or more rows in the ContactsContract.Data table. Each data row has a column Data.RAW_CONTACT_ID that contains the RawContacts._ID value of its parent ContactsContract.RawContacts row.

 

一个原始电话簿的大多数数据不存储在ContactsContract.RawContacts表中。相反,它被存储在ContactsContract.Data表中的一个或多个行。每个数据行拥有一个列Data.RAW_CONTACT_ID,它包含它的父ContactsContract.RawContacts行的RawContacts._ID值。

 

Important raw contact columns

 

重要的原始电话簿列

 

The important columns in the ContactsContract.RawContacts table are listed in table 1. Please read the notes that follow after the table:

 

在ContactsContract.RawContacts中重要的列被列举在表1中。请阅读跟在表后的备注:

 

Table 1. Important raw contact columns.

 

表1. 重要的原始电话簿列。

 

-------------------------------

 

Column name UseNotes

 

列名 用法 备注

 

ACCOUNT_NAME  

The account name for the account type that's the source of this raw contact. For example, the account name of a Google account is one of the device owner's Gmail addresses. See the next entry for ACCOUNT_TYPE for more information.   

The format of this name is specific to its account type. It is not necessarily an email address.

 

ACCOUNT_NAME 

作为这个原始电话簿的源的账户类型的账户名称。例如,一个Google账户的账户名称是设备拥有者的其中一个Gmail邮箱地址。参见下一个ACCOUNT_TYPE的记录以获得更多信息。

这个名称的格式被指定为它的账户类型。它不必是一个电子邮箱地址。

 

ACCOUNT_TYPE  

The account type that's the source of this raw contact. For example, the account type of a Google account is com.google. Always qualify your account type with a domain identifier for a domain you own or control. This will ensure that your account type is unique. 

An account type that offers contacts data usually has an associated sync adapter that synchronizes with the Contacts Provider.

 

ACCOUNT_TYPE 

作为这个原始电话簿的源的账户类型。例如,一个Google账户的账户类型是com.google。总是用你拥有或控制的域名的一个域名标识符修饰你的账户类型。这将确保你的账户类型是唯一的。

一个提供电话簿数据的账户类型通常拥有一个被关联的用电话簿提供者来同步的同步适配器。

 

DELETED  

The "deleted" flag for a raw contact. 

This flag allows the Contacts Provider to maintain the row internally until sync adapters are able to delete the row from their servers and then finally delete the row from the repository.

 

DELETED 

一个原始电话簿的“已删除”标志。 

这个标志允许电话簿提供者内部地维护行,直至同步适配器能够从它们的服务器中删除行,然后最终从仓库中删除该行。

 

-------------------------------

 

Notes

 

注意

 

The following are important notes about the ContactsContract.RawContacts table:

 

以下是关于ContactsContract.RawContacts表的重要注意事项:

 

* A raw contact's name is not stored in its row in ContactsContract.RawContacts. Instead, it's stored in the ContactsContract.Data table, in a ContactsContract.CommonDataKinds.StructuredName row. A raw contact has only one row of this type in the ContactsContract.Data table.

 

* 一个原始电话簿的名称不被存储在它在ContactsContract.RawContacts中的行。相反,它被存储在ContactsContract.Data表中,在一个ContactsContract.CommonDataKinds.StructuredName行中。一个原始电话簿在ContactsContract.Data表中只拥有这个类型的一个行。

 

* Caution: To use your own account data in a raw contact row, it must first be registered with the AccountManager. To do this, prompt users to add the account type and their account name to the list of accounts. If you don't do this, the Contacts Provider will automatically delete your raw contact row.

 

* 警告:为了在一个原始电话簿行中使用你自己的账户数据,必须首先用AccountManager注册它。为了做到这点,提示用户添加账户类型和他们的账户名称至账户列表。如果你不做这个,电话簿提供者将自动地删除你的原始电话簿行。

 

For example, if you want your app to maintain contacts data for your web-based service with the domain com.example.dataservice, and the user's account for your service is [email protected], the user must first add the account "type" (com.example.dataservice) and account "name" ([email protected]) before your app can add raw contact rows. You can explain this requirement to the user in documentation, or you can prompt the user to add the type and name, or both. Account types and account names are described in more detail in the next section.

 

例如,如果你希望你的应用为你的域名为com.example.dataservice的基于Web的服务维护电话簿数据,而你的服务的用户账户为[email protected],那么用户必须在你的应用可以添加原始电话簿行之前,首先添加账户“类型”(com.example.dataservice)和账户“名称”([email protected])。你可以在文档中解释这个要求给用户,或者你可以提示用户添加类型和名称,或者两者都做。账户类型和账户名称被更详细地描述在下一章节中。

 

Sources of raw contacts data

 

原始电话簿数据的源

 

To understand how raw contacts work, consider the user "Emily Dickinson" who has the following three user accounts defined on her device:

 

为了理解原始电话簿如何工作,考虑用户“艾米莉·狄更生”(注:一位美国女诗人),她拥有以下定义在她的设备上的三个用户账户:

 

[email protected]

 

[email protected]

 

* Twitter account "belle_of_amherst"   Twitter账户"belle_of_amherst"(注:阿默斯特的女尼,文史上称狄更生为“阿默斯特的女尼”)

 

This user has enabled Sync Contacts for all three of these accounts in the Accounts settings.

 

这个用户为账户设置中全部三个账户都已经使能了同步电话簿。

 

Suppose Emily Dickinson opens a browser window, logs into Gmail as [email protected], opens Contacts, and adds "Thomas Higginson". Later on, she logs into Gmail as [email protected] and sends an email to "Thomas Higginson", which automatically adds him as a contact. She also follows "colonel_tom" (Thomas Higginson's Twitter ID) on Twitter.

 

假设艾米莉·迪金森打开一个浏览器窗口,登陆进Gmail作为[email protected],打开电话簿,并且添加“托马斯·希金森”。后来,她登陆进Gmail作为[email protected],并发送一个电子邮件到“托马斯·希金森”,它自动地添加他作为一个电话簿。她还追随"colonel_tom"(注:汤姆上校)(托马斯·希金森的Twitter ID)在Twitter上。

 

The Contacts Provider creates three raw contacts as a result of this work:

 

电话簿提供者创建三个原始电话簿作为这个工作的结果:

 

1. A raw contact for "Thomas Higginson" associated with [email protected]. The user account type is Google.

 

1. 一个"Thomas Higginson"的原始电话簿关联[email protected]。用户账户类型为Google。

 

2. A second raw contact for "Thomas Higginson" associated with [email protected]. The user account type is also Google. There is a second raw contact even though the name is identical to a previous name, because the person was added for a different user account.

 

2. 与[email protected]关联的“托马斯·希金森”(注:美国作家)的第二原始电话簿。用户账户类型也是Google。存在一个第二原始电话簿,即便该名称与前一个名称相同,因为为了一个不同的用户账户而添加那个人。

 

3. A third raw contact for "Thomas Higginson" associated with "belle_of_amherst". The user account type is Twitter.

 

3. 第三个"Thomas Higginson"的原始电话簿与"belle_of_amherst"关联。用户账户类型是Twitter。

 

-------------------------------

 

Data

 

数据

 

As noted previously, the data for a raw contact is stored in a ContactsContract.Data row that is linked to the raw contact's _ID value. This allows a single raw contact to have multiple instances of the same type of data such as email addresses or phone numbers. For example, if "Thomas Higginson" for [email protected] (the raw contact row for Thomas Higginson associated with the Google account [email protected]) has a home email address [email protected] and a work email address of [email protected], the Contacts Provider stores the two email address rows and links them both to the raw contact.

 

正如前面所述,一个原始电话簿的数据别存储在一个ContactsContract.Data行,它被链接到原始电话簿的_ID值。这允许一个单一原始电话簿拥有多个相同类型数据的多个实例,诸如电子邮箱导致或电话号码。例如,如果“托马斯·希金森”对应[email protected](托马斯·希金森的原始电话簿行与Google账户[email protected]关联)拥有一个[email protected]的家庭电子邮箱地址以及一个[email protected]的工作电子邮箱地址,那么电话簿提供者存储两个电子邮箱地址行并链接它们两者到原始电话簿。

 

Notice that different types of data are stored in this single table. Display name, phone number, email, postal address, photo, and website detail rows are all found in the ContactsContract.Data table. To help manage this, the ContactsContract.Data table has some columns with descriptive names, and others with generic names. The contents of a descriptive-name column have the same meaning regardless of the type of data in the row, while the contents of a generic-name column have different meanings depending on the type of data.

 

注意,不同类型数据被存储在这个电议表中。显示名称,电话号码,电子邮件,邮政地址,照片,以及网站明细行都在ContactsContract.Data表中被找到。为了帮助管理它,ContactsContract.Data表拥有一些带描述名称的列,而其它带有一般名称。一个可描述名称列的内容拥有相同的意思不管行中的数据类型是什么。然而一个一般名称列的内容拥有不同的意思,依赖于数据类型。

 

Descriptive column names

 

描述的行名称

 

Some examples of descriptive column names are:

 

一些示例的描述的行名称有:

 

RAW_CONTACT_ID

 

The value of the _ID column of the raw contact for this data.

 

这个数据的原始电话簿的_ID列的值。

 

MIMETYPE

 

The type of data stored in this row, expressed as a custom MIME type. The Contacts Provider uses the MIME types defined in the subclasses of ContactsContract.CommonDataKinds. These MIME types are open source, and can be used by any application or sync adapter that works with the Contacts Provider.

 

存储在这个行的数据的类型,被表达为一个定制MIME类型。电话簿提供者使用定义在ContactsContract.CommonDataKinds子类中的MIME类型。这些MIME类型是开源的,而且可以被任意处理电话簿提供者的应用程序或同步适配器使用。

 

IS_PRIMARY

 

If this type of data row can occur more than once for a raw contact, the IS_PRIMARY column flags the data row that contains the primary data for the type. For example, if the user long-presses a phone number for a contact and selects Set default, then the ContactsContract.Data row containing that number has its IS_PRIMARY column set to a non-zero value.

 

如果这个类型的数据行对于一个原始电话簿来说可以出现多于一次,那么IS_PRIMARY列标志着数据包含该类型的主要数据(注:待考)。例如,如果用户为一个电话簿而长按一个电话号码,并且选择设置默认,那么包含那个号码的ContactsContract.Data行让它的IS_PRIMARY列设置为非0值。

 

Generic column names

 

一般列名

 

There are 15 generic columns named DATA1 through DATA15 that are generally available and an additional four generic columns SYNC1 through SYNC4 that should only be used by sync adapters. The generic column name constants always work, regardless of the type of data the row contains.

 

存在15个被命名为DATA1至DATA15的一般列,它们通常是可用的而且额外的四个一般列SYNC1至SYNC4应该只被同步适配器使用。一般列名常量总是工作的,不管该行包含数据的类型是什么。

 

The DATA1 column is indexed. The Contacts Provider always uses this column for the data that the provider expects will be the most frequent target of a query. For example, in an email row, this column contains the actual email address.

 

DATA1列被索引。总是为了提供者期待的数据而使用这个列的电话簿提供者将是一个查询最常见的目标。例如,在一个电子邮件行中,这个列包含实际电子邮件地址。

 

By convention, the column DATA15 is reserved for storing Binary Large Object (BLOB) data such as photo thumbnails.

 

约定下,列DATA15被保留用于存储二进制大对象(BLOB)数据诸如照片缩略图。

 

Type-specific column names

 

类型特定列名称

 

To facilitate working with the columns for a particular type of row, the Contacts Provider also provides type-specific column name constants, defined in subclasses of ContactsContract.CommonDataKinds. The constants simply give a different constant name to the same column name, which helps you access data in a row of a particular type.

 

为了方便处理一个特殊类型行的列,电话簿提供者还提供类型特定列名称常量,定义在ContactsContract.CommonDataKinds的子类中。常量简单地给予一个不同的常量名称给相同的列名,它有助于你访问一个特殊类型的行中的数据。

 

For example, the ContactsContract.CommonDataKinds.Email class defines type-specific column name constants for a ContactsContract.Data row that has the MIME type Email.CONTENT_ITEM_TYPE. The class contains the constant ADDRESS for the email address column. The actual value of ADDRESS is "data1", which is the same as the column's generic name.

 

例如,ContactsContract.CommonDataKinds.Email类为一个拥有MIME类型Email.CONTENT_ITEM_TYPE的ContactsContract.Data定义类型特定列名常量。该类为电子邮件地址列包含常量ADDRESS。ADDRESS的实际值是"data1",它与列的一般名称相同。

 

-------------------------------

 

Caution: Don't add your own custom data to the ContactsContract.Data table using a row that has one of the provider's pre-defined MIME types. If you do, you may lose the data or cause the provider to malfunction. For example, you should not add a row with the MIME type Email.CONTENT_ITEM_TYPE that contains a user name instead of an email address in the column DATA1. If you use your own custom MIME type for the row, then you are free to define your own type-specific column names and use the columns however you wish.

 

警告:不要使用拥有其中一种提供者预定义MIME类型的一个行来添加你自己的自定义数据到ContactsContract.Data表。如果你这样做,你可能丢失数据或导致提供者故障。例如,你不应该添加一个包含用户名的带MIME类型Email.CONTENT_ITEM_TYPE的行取代一个在列DATA1中的一个电子邮箱地址。如果你对该行使用你自己的自定义MIME类型,那么你有自由定义你自己的类型特定列名并使用那些列不管你希望怎样。

 

-------------------------------

 

Figure 2 shows how descriptive columns and data columns appear in a ContactsContract.Data row, and how type-specific column names "overlay" the generic column names

 

图2展示描述性列和数据列如何出现在ContactsContract行,以及类型特定列如何把“覆盖层”(注:抽象层?)命名为一般列名。

 

(图2略:

左:

CommonDataKinds.Email

RAW_CONTACT_ID

MIMETYPE

IS_PRIMARY

...

Address (映射到DATA1)

Tpe (映射到DATA2)

Label  (映射到DATA3)

...

右:

ContactsContact.DATA

RAW_CONTACT_ID

MIMETYPE

IS_PRIMARY

...

DATA1

DATA2

DATA3

...

DATA15

 

Figure 2. Type-specific column names and generic column names.

 

图2. 类型特定列名称和通用列名称。

 

Type-specific column name classes

 

类型特定列名称类。

 

Table 2 lists the most commonly-used type-specific column name classes:

 

表2列举大多数常用类型特定列名称类:

 

Table 2. Type-specific column name classes

 

表2. 类型特定的列名称类

 

-------------------------------

 

Mapping class Type of dataNotes

 

映射类 数据类型 注意事项

 

ContactsContract.CommonDataKinds.StructuredName

The name data for the raw contact associated with this data row.

A raw contact has only one of these rows.

 

ContactsContract.CommonDataKinds.StructuredName

关联这个数据行的原始电话簿的名称数据。

一个原始电话簿只拥有这些行中的其中一个。

 

ContactsContract.CommonDataKinds.Photo

The main photo for the raw contact associated with this data row.

A raw contact has only one of these rows.

 

ContactsContract.CommonDataKinds.Photo

关联这个数据行的原始电话簿的主要照片。

一个原始电话簿只拥有这些行中的其中一个。

 

ContactsContract.CommonDataKinds.Email

An email address for the raw contact associated with this data row.

A raw contact can have multiple email addresses.

 

ContactsContract.CommonDataKinds.Email

关联这个数据行的原始电话簿的一个电子邮箱地址。

一个原始电话簿可以拥有多个电子邮箱地址。

 

ContactsContract.CommonDataKinds.StructuredPostal

A postal address for the raw contact associated with this data row.

A raw contact can have multiple postal addresses.

 

ContactsContract.CommonDataKinds.StructuredPostal

关联这个数据行的原始电话簿的一个邮政地址。

一个原始电话簿可以拥有多个邮政地址。

 

ContactsContract.CommonDataKinds.GroupMembership

An identifier that links the raw contact to one of the groups in the Contacts Provider. 

Groups are an optional feature of an account type and account name. They're described in more detail in the section Contact groups.

 

ContactsContract.CommonDataKinds.GroupMembership

一个唯一标识符,它链接原始电话簿到电话簿提供者中组的其中一个。

组是一个账户类型和账户名称的一个可选特性。它们在章节电话簿组中被更详细地描述。

 

-------------------------------

 

Contacts

 

电话簿

 

The Contacts Provider combines the raw contact rows across all account types and account names to form a contact. This facilitates displaying and modifying all the data a user has collected for a person. The Contacts Provider manages the creation of new contact rows, and the aggregation of raw contacts with an existing contact row. Neither applications nor sync adapters are allowed to add contacts, and some columns in a contact row are read-only.

 

电话簿提供者跨越所有账户类型和账户名称来组合原始电话簿行以形成一个电话簿。这方便显示和修改一个用户曾经为一个人而收集的所有数据。电话簿提供者管理新电话簿行的创建,以及带有一个现存电话簿行的原始电话簿的聚集。不管是应用程序还是同步适配器,都不允许添加电话簿,而在一个电话簿行中一些列是只读的。

 

-------------------------------

 

Note: If you try to add a contact to the Contacts Provider with an insert(), you'll get an UnsupportedOperationException exception. If you try to update a column that's listed as "read-only," the update is ignored.

 

注意:如果你尝试用一个insert()添加一个电话簿到电话薄提供者,那么你将获得一个UnsupportedOperationException异常。如果你尝试更新一个被列举作为“只读”的列,那么更新被忽略。

 

-------------------------------

 

The Contacts Provider creates a new contact in response to the addition of a new raw contact that doesn't match any existing contacts. The provider also does this if an existing raw contact's data changes in such a way that it no longer matches the contact to which it was previously attached. If an application or sync adapter creates a new raw contact that does match an existing contact, the new raw contact is aggregated to the existing contact.

 

电话簿提供者创建一个新的电话簿以响应不适配任意现存电话簿的一个新原始电话簿的添加。提供者还这样做,如果一个现存原始电话簿数据以这样一种方式改变,它不再匹配到它之前被依附到的电话簿。如果一个应用程序或同步适配器创建一个新原始电话簿,它撇皮一个现存电话簿,那么新原始电话簿被聚集到现存电话簿。

 

The Contacts Provider links a contact row to its raw contact rows with the contact row's _ID column in the Contacts table. The CONTACT_ID column of the raw contacts table ContactsContract.RawContacts contains _ID values for the contacts row associated with each raw contacts row.

 

电话簿提供者用电话簿表中电话簿行的_ID列来链接一个电话簿行与它的原始电话簿行。原始电话簿表ContactsContract.RawContacts的CONTACT_ID列包含与每个原始电话簿行关联的电话簿的_ID值。

 

The ContactsContract.Contacts table also has the column LOOKUP_KEY that is a "permanent" link to the contact row. Because the Contacts Provider maintains contacts automatically, it may change a contact row's _ID value in response to an aggregation or sync. Even If this happens, the content URI CONTENT_LOOKUP_URI combined with contact's LOOKUP_KEY will still point to the contact row, so you can use LOOKUP_KEY to maintain links to "favorite" contacts, and so forth. This column has its own format that is unrelated to the format of the _ID column.

 

ContactsContract.Contacts表还有列LOOKUP_KEY,它是一个指到电话簿行的“永久”链接。因为电话簿提供者自动地维护电话簿,所以它可能改变一个电话簿行的_ID值以响应一次聚集或同步。即便它发生了,组合电话簿的LOOKUP_KEY的内容URI CONTENT_LOOKUP_URI将仍然指向电话簿行,所以你可以使用LOOKUP_KEY来维护指向“收藏”电话簿的链接,等等。这个列拥有它自己的与_ID列的格式无关的格式,

 

Figure 3 shows how the three main tables relate to each other.

 

图3展示三个主表如何互相关联。

 

(图3略:

托马斯·希金森(电话簿)

-> 原始电话簿(托马斯·希金森) [email protected] Google

->数据 托马斯·希金森 StructuredName

->电子邮箱 [email protected]

->电子邮箱 [email protected]

-> 原始电话簿(托马斯·希金森)[email protected] Google

-> 原始电话簿(colonel_tom)amberstbelle Twitter

 

Figure 3. Contacts, Raw Contacts, and Details table relationships.

 

图3. 电话簿,原始电话簿,和明细表的关系。

 

-------------------------------

 

Data From Sync Adapters

 

来自同步适配器的数据

 

Users enter contacts data directly into the device, but data also flows into the Contacts Provider from web services via sync adapters, which automate the transfer of data between the device and services. Sync adapters run in the background under the control of the system, and they call ContentResolver methods to manage data.

 

用户直接地输入电话簿数据进设备中,但数据还通过同步适配器流进来自web服务的电话簿提供者,它自动化设备和服务之间数据的传输。同步适配器在系统的控制下运行于后台中,而且它们调用ContentResolver的方法来管理数据。

 

In Android, the web service that a sync adapter works with is identified by an account type. Each sync adapter works with one account type, but it can support multiple account names for that type. Account types and account names are described briefly in the section Sources of raw contacts data. The following definitions offer more detail, and describe how account type and name relate to sync adapters and services.

 

在Android中,一个同步适配器处理的web服务被一个账户类型标识。每个同步适配器处理一个账户类型,但它可以支持这个类型的多账户名称。账户类型和账户名称在章节原始电话簿数据的源中被简短地描述。以下定义提供更多细节,并且描述账户类型和名称如何关联到同步适配器和服务。

 

Account type

 

账户类型

 

Identifies a service in which the user has stored data. Most of the time, the user has to authenticate with the service. For example, Google Contacts is an account type, identified by the code google.com. This value corresponds to the account type used by AccountManager.

 

标识一个用户已经在其中存储数据的服务。大多数时候,用户不得不使用服务来验证。例如,Google电话簿(注:官方的正式称呼是Google通信录)是一个账户类型,由代码google.com标识。这个值对应AccountManager使用的账户类型。

 

Account name

 

账户名称

 

Identifies a particular account or login for an account type. Google Contacts accounts are the same as Google accounts, which have an email address as an account name. Other services may use a single-word username or numeric id.

 

标识一个特殊账号或一个账户类型的登录。Google电话簿账户和Google账户相同,它拥有一个电子邮件地址作为一个账户名。其它服务可以使用一个单字用户名或数字id。

 

Account types don't have to be unique. A user can configure multiple Google Contacts accounts and download their data to the Contacts Provider; this may happen if the user has one set of personal contacts for a personal account name, and another set for work. Account names are usually unique. Together, they identify a specific data flow between the Contacts Provider and an external service.

 

账户类型不必是唯一的。一个用户可以配置多个Google通信录账户并下载他们的数据到电话簿提供者;这可能发生,如果用户拥有一个个人账户名称的一组个人电话簿,以及另一组用于工作。账户名称通常是唯一的。它们一起标识在电话簿提供者和一个外部服务之间的一个特定数据流。

 

If you want to transfer your service's data to the Contacts Provider, you need to write your own sync adapter. This is described in more detail in the section Contacts Provider Sync Adapters.

 

如果你想传递你的服务的数据给内容提供者,你需要编写你自己的同步适配器。在章节电话簿提供者同步适配器中会更详细地描述它。

 

Figure 4 shows how the Contacts Provider fits into the flow of data about people. In the box marked "sync adapters," each adapter is labeled by its account type.

 

图4展示电话簿提供者如何适配进关于人的数据流中。在标记为“同步适配器”的盒子中,每个适配器被它的账户类型所标签。

 

(图4略:

联系人应用 <->               <-> gmail.com <-> Google通信录

应用       <-> 电话簿提供者  <-> gmail.com <-> Google+

应用       <->               <-> example.com <-> Exchange

                             <-> myacct <-> Twitter

...                              ...         ...

 

                                 同步适配器  服务器

 

 

Figure 4. The Contacts Provider flow of data.

 

图1. 数据的电话簿提供者流

 

-------------------------------

 

Required Permissions

 

必需的权限

 

Applications that want to access the Contacts Provider must request the following permissions:

 

希望访问电话簿提供者的应用程序必须请求以下权限:

 

Read access to one or more tables

 

对一个或多个表的读取权限

 

READ_CONTACTS, specified in AndroidManifest.xml with the element as .

 

READ_CONTACTS,在AndroidManifest.xml中被指定,使用元素,作为

 

Write access to one or more tables

 

对一个或多个表的写入权限

 

WRITE_CONTACTS, specified in AndroidManifest.xml with the element as .

 

WRITE_CONTACTS,在AndroidManifest.xml中用元素来指定,作为

 

These permissions do not extend to the user profile data. The user profile and its required permissions are discussed in the following section, The User Profile.

 

这些权限不扩展到用户简介数据。用户简介和它的必需权限在下一章节用户简介中讨论。

 

Remember that the user's contacts data is personal and sensitive. Users are concerned about their privacy, so they don't want applications collecting data about them or their contacts. If it's not obvious why you need permission to access their contacts data, they may give your application low ratings or simply refuse to install it.

 

记住用户的电话簿数据是个人的和敏感的。用户关心他们的隐私,所以他们不希望应用程序收集关于他们或他们的电话簿的数据。如果你需要权限来访问他们的电话簿数据的理由不是明显的,那么他们可能给你的应用程序低的评级或简单地拒绝安装它。

 

-------------------------------

 

The User Profile

 

用户简介

 

The ContactsContract.Contacts table has a single row containing profile data for the device's user. This data describes the device's user rather than one of the user's contacts. The profile contacts row is linked to a raw contacts row for each system that uses a profile. Each profile raw contact row can have multiple data rows. Constants for accessing the user profile are available in the ContactsContract.Profile class.

 

ContactsContract.Contacts表拥有一个单一行包含设备用户的简介数据。这个数据描述设备用户而非其中一个用户的电话簿。简介电话簿行被链接到每个使用简介的系统的一个原始电话簿行。每个简介原始电话簿行可以拥有多个数据行。访问用户简介的常量在ContactsContract.Profile类中可用。

 

Access to the user profile requires special permissions. In addition to the READ_CONTACTS and WRITE_CONTACTS permissions needed to read and write, access to the user profile requires the READ_PROFILE and WRITE_PROFILE permissions for read and write access, respectively.

 

访问用户简介需要一些特殊的权限。除了需要READ_CONTACTS和WRITE_CONTACTS权限来读写外,访问用户简介还需要READ_PROFILE和WRITE_PROFILE权限分别用于读写访问权。

 

Remember that you should consider a user's profile to be sensitive. The permission READ_PROFILE allows you to access the device user's personally-identifying data. Make sure to tell the user why you need user profile access permissions in the description of your application.

 

记住你应该考虑一个用户的简介是敏感的。权限READ_PROFILE允许你访问设备用户的个人标识数据。确保在你的应用程序的描述中告诉用户你为什么需要用户简介的访问权限。

 

To retrieve the contact row that contains the user's profile, call ContentResolver.query(). Set the content URI to CONTENT_URI and don't provide any selection criteria. You can also use this content URI as the base URI for retrieving raw contacts or data for the profile. For example, this snippet retrieves data for the profile:

 

为了取出包含用户简介的电话簿行,请调用ContentResolver.query()。设置内容URI为CONTENT_URI并且不提供任意选择条件。你还可以使用这个内容URI作为基URI以取出简介的原始电话簿或数据。例如,这个代码片段取出简介的数据:

 

-------------------------------

 

// Sets the columns to retrieve for the user profile

// 设置列名以取出用户简介

mProjection = new String[]

    {

        Profile._ID,

        Profile.DISPLAY_NAME_PRIMARY,

        Profile.LOOKUP_KEY,

        Profile.PHOTO_THUMBNAIL_URI

    };

 

// Retrieves the profile from the Contacts Provider

// 从电话簿提供者中取出简介

mProfileCursor =

        getContentResolver().query(

                Profile.CONTENT_URI,

                mProjection ,

                null,

                null,

                null);

 

-------------------------------

 

-------------------------------

 

Note: If you retrieve multiple contact rows, and you want to determine if one of them is the user profile, test the row's IS_USER_PROFILE column. This column is set to "1" if the contact is the user profile.

 

注意:如果你取出多个电话簿行,而你希望确定它们之一是否是用户简介,请测试该行的IS_USER_PROFILE列。这个列被设置为"1"如果电话簿是用户简介。

 

-------------------------------

 

-------------------------------

 

Contacts Provider Metadata

 

电话簿提供者元数据

 

The Contacts Provider manages data that keeps track of the state of contacts data in the repository. This metadata about the repository is stored in various places, including the Raw Contacts, Data, and Contacts table rows, the ContactsContract.Settings table, and the ContactsContract.SyncState table. The following table shows the effect of each of these pieces of metadata:

 

电话簿提供者管理保持跟踪仓库中电话簿数据状态的数据。这个关于仓库的元数据被保存在不同的地方,包括原始电话簿,数据,和电话簿表行,ContactsContract.Settings表,以及ContactsContract.SyncState表。以下表格展示这些元数据块中每一个的效果。

 

Table 3. Metadata in the Contacts Provider

 

表3. 电话簿提供者中的元数据

 

-------------------------------

 

Table ColumnValues Meaning

 

表 列 值 含义

 

ContactsContract.RawContacts

DIRTY

"0" - not changed since the last sync. 

"1" - changed since last sync, needs to be synced back to the server.

Marks raw contacts that were changed on the device and have to be synced back to the server. The value is set automatically by the Contacts Provider when Android applications update a row.

Sync adapters that modify the raw contact or data tables should always append the string CALLER_IS_SYNCADAPTER to the content URI they use. This prevents the provider from marking rows as dirty. Otherwise, sync adapter modifications appear to be local modifications and are sent to the server, even though the server was the source of the modification.

 

ContactsContract.RawContacts

DIRTY

"0"——从最后一次同步开始不被改变。 

"1"——从上一次同步开始被改变,需要被同步回到服务器。

标注在设备上被改变且必须被同步回服务器的原始电话簿。该值被电话簿提供者自动地设置,当Android应用程序更新一个行时。

修改原始电话簿或数据表的同步适配器应该总是尾加字符串CALLER_IS_SYNCADAPTER到它们使用的内容URI。它阻止提供者标注行为脏的。否则,同步适配器的修改显得是本地修改并被发送到服务器,即便服务器是修改的源。

 

ContactsContract.RawContacts

VERSION

The version number of this row. 

The Contacts Provider automatically increments this value whenever the row or its related data changes.

 

ContactsContract.RawContacts 

VERSION 

这个行的版本号。 

电话簿提供者自动地增加这个值,每当该行或它的相关数据改变时。

 

ContactsContract.Data

DATA_VERSION

The version number of this row. 

The Contacts Provider automatically increments this value whenever the data row is changed.

 

ContactsContract.Data

DATA_VERSION 

这个行的版本号 

电话簿提供者自动地增加这个值每当数据行被改变。

 

ContactsContract.RawContacts

SOURCE_ID 

A string value that uniquely identifies this raw contact to the account in which it was created. 

When a sync adapter creates a new raw contact, this column should be set to the server's unique ID for the raw contact. When an Android application creates a new raw contact, the application should leave this column empty. This signals the sync adapter that it should create a new raw contact on the server, and get a value for the SOURCE_ID.

In particular, the source id must be unique for each account type and should be stable across syncs:

 

ContactsContract.RawContacts 

SOURCE_ID 

一个唯一地标识这个原始电话簿至它被创建在的账户的字符串值。 

当一个同步适配器创建一个新的原始电话簿,这个列应该被设置为原始电话簿的服务器唯一ID。当一个Android应用程序创建一个新的原始电话簿时,应用程序应该让这个列保持为空。它通知同步适配器它应该在服务器上创建一个新的原始电话簿,并为SOURCE_ID获得一个值。

特别地,源id对于每个账户类型来说必须是唯一的并且应该是跨同步稳定的:

 

* Unique: Each raw contact for an account must have its own source id. If you don't enforce this, you'll cause problems in the contacts application. Notice that two raw contacts for the same account type may have the same source id. For example, the raw contact "Thomas Higginson" for the account [email protected] is allowed to have the same source id as the raw contact "Thomas Higginson" for the account [email protected].

 

* 唯一的:一个账户的每个原始电话簿必须拥有它自己的源id,如果你不实施它,你将导致电话簿应用程序中的问题。注意相同账户类型的两个原始电话簿可能有相同的源id。例如,账户[email protected]的原始电话簿“托马斯·希金森”被允许拥有与账户[email protected]的原始电话簿“托马斯·希金森”相同的源id。

 

* Stable: Source ids are a permanent part of the online service's data for the raw contact. For example, if the user clears Contacts Storage from the Apps settings and re-syncs, the restored raw contacts should have the same source ids as before. If you don't enforce this, shortcuts will stop working.

 

* 稳定的:源id是原始电话簿的在线服务数据的一个永久部分。例如,如果用户从应用设置中清空电话簿存储并重新同步,被存储的原始电话簿应该拥有和之前相同的源id。如果你不实施它,快捷方式将停止工作。

 

ContactsContract.Groups

GROUP_VISIBLE

"0" - Contacts in this group should not be visible in Android application UIs. 

"1" - Contacts in this group are allowed to be visible in application UIs.

This column is for compatibility with servers that allow a user to hide contacts in certain groups.

 

ContactsContract.Groups

GROUP_VISIBLE

"0"——这个组的电话簿在Android应用程序用户界面中不应该是可见的

"1"——这个组中的电话簿被允许在应用程序用户界面中是可见的。

这个列是用于兼容允许一个用户在某些组中隐藏电话簿的服务器。

 

ContactsContract.Settings

UNGROUPED_VISIBLE 

"0" - For this account and account type, contacts that don't belong to a group are invisible to Android application UIs. 

"1" - For this account and account type, contacts that don't belong to a group are visible to application UIs.

By default, contacts are invisible if none of their raw contacts belongs to a group (Group membership for a raw contact is indicated by one or more ContactsContract.CommonDataKinds.GroupMembership rows in the ContactsContract.Data table). By setting this flag in the ContactsContract.Settings table row for an account type and account, you can force contacts without groups to be visible. One use of this flag is to show contacts from servers that don't use groups.

 

ContactsContract.Settings

UNGROUPED_VISIBLE 

"0"——对于这个账户和账户类型,不属于一个组的电话簿对于Android应用程序用户界面来说是不可见的。 

"1"——对于这个账户和账户类型,不属于一个组的电话簿对于应用程序用户界面来说是可见的。

默认,电话簿是不可见的如果它们的原始电话簿都不属于一个组(一个原始电话簿的组成员被ContactsContract.Data表中一个或多个ContactsContract.CommonDataKinds.GroupMembership行指示)。通过在ContactsContract.Settings表行中为一个账户类型和账户设置这个标志,你可以强制让没有组的电话簿可见。这个标志的其中一个用途是展示不使用组的来自服务器的电话簿。

 

ContactsContract.SyncState

(all) 

Use this table to store metadata for your sync adapter. 

With this table you can store sync state and other sync-related data persistently on the device.

 

ContactsContract.SyncState 

(所有) 

使用这个表以存储你的同步适配器的元数据。 

使用这个表,你可以持久地存储同步状态和其它同步相关的数据在设备上。

 

-------------------------------

 

Contacts Provider Access

 

电话簿提供者访问

 

This section describes guidelines for accessing data from the Contacts Provider, focusing on the following:

 

这个章节描述用于访问来自电话簿提供者的数据的指南,关注以下内容:

 

* Entity queries.

 

* 实体查询。

 

* Batch modification.

 

* 批量修改

 

* Retrieval and modification with intents.

 

* 使用意图的检索和修改。

 

* Data integrity.

 

* 数据完整性。

 

Making modifications from a sync adapter is also covered in more detail in the section Contacts Provider Sync Adapters.

 

从一个同步适配器中作出改变还在章节电话簿提供者同步适配器中被更详细地涵盖。

 

Querying entities

 

查询实体

 

Because the Contacts Provider tables are organized in a hierarchy, it's often useful to retrieve a row and all of the "child" rows that are linked to it. For example, to display all the information for a person, you may want to retrieve all the ContactsContract.RawContacts rows for a single ContactsContract.Contacts row, or all the ContactsContract.CommonDataKinds.Email rows for a single ContactsContract.RawContacts row. To facilitate this, the Contacts Provider offers entity constructs, which act like database joins between tables.

 

因为电话簿提供者表被组织成一个层级,所以取出一个行和所有链接到它的“子”行常常是有用的。例如,为了显示关于一个人的所有信息,你可能希望取出一个单一ContactsContract.Contacts行的所有ContactsContract.RawContacts行,或者一个单一ContactsContract.RawContacts行的所有ContactsContract.CommonDataKinds.Email行。为了方便这样做,电话簿提供者提供实体构造,它的行为像表之间的数据库连接。

 

An entity is like a table composed of selected columns from a parent table and its child table. When you query an entity, you supply a projection and search criteria based on the columns available from the entity. The result is a Cursor that contains contains one row for each child table row that was retrieved. For example, if you query ContactsContract.Contacts.Entity for a contact name and all the ContactsContract.CommonDataKinds.Email rows for all the raw contacts for that name, you get back a Cursor containing one row for each ContactsContract.CommonDataKinds.Email row.

 

一个实体就像一个表,由来自一个父表和它的子表中的选中列组成。当你查询一个实体时,你基于实体中可用的列提供一个投影和搜索条件。结果是一个Cursor,它包含(注:此处多了一个contains)取出的每个子表行的一个行。例如,如果你查询ContactsContract.Contacts.Entity的一个电话簿名称和那个名称的所有原始电话簿的所有ContactsContract.CommonDataKinds.Email行,你取回一个Cursor,它包含每个ContactsContract.CommonDataKinds.Email行的一个行。

 

Entities simplify queries. Using an entity, you can retrieve all of the contacts data for a contact or raw contact at once, instead of having to query the parent table first to get an ID, and then having to query the child table with that ID. Also, the Contacts Provider processes a query against an entity in a single transaction, which ensures that the retrieved data is internally consistent.

 

实体简化查询。使用一个实体,你可以马上取出一个电话簿或原始电话簿的所有电话簿内容,而不必首先查询父表以获得一个ID,然后必须用那个ID查询子表。还有,电话簿提供者在一个单一事务中处理一次针对实体的查询,这确保取出的数据是内部一致的。

 

-------------------------------

 

Note: An entity usually doesn't contain all the columns of the parent and child table. If you attempt to work with a column name that isn't in the list of column name constants for the entity, you'll get an Exception.

 

注意:一个实体通常不包含父表和子表的所有列,如果你尝试使用一个不再实体的列名常量列表中的列名,你将得到一个Exception。

 

-------------------------------

 

The following snippet shows how to retrieve all the raw contact rows for a contact. The snippet is part of a larger application that has two activities, "main" and "detail". The main activity shows a list of contact rows; when the user select one, the activity sends its ID to the detail activity. The detail activity uses the ContactsContract.Contacts.Entity to display all of the data rows from all of the raw contacts associated with the selected contact.

 

以下代码片段展示如何取出一个电话簿的所有原始电话簿行。该代码片段是一个拥有两个活动,“主要”和“明细”,的较大应用程序的一部分。主活动展示电话簿行的一个列表;当用户选择一个时,活动发送它的ID给明细活动。明细活动使用ContactsContract.Contacts.Entity以显示来自与选中电话簿有关的所有原始电话簿的所有数据行。

 

This snippet is taken from the "detail" activity:

 

这个代码片段取自“明细”活动

 

-------------------------------

 

...

    /*

     * Appends the entity path to the URI. In the case of the Contacts Provider, the

     * expected URI is content://com.google.contacts/#/entity (# is the ID value).

     * 尾加实体路径到URI。在电话簿提供者的情况下,

     * 期待的URI是content://com.google.contacts/#/entity(#是ID值)。

     */

    mContactUri = Uri.withAppendedPath(

            mContactUri,

            ContactsContract.Contacts.Entity.CONTENT_DIRECTORY);

 

    // Initializes the loader identified by LOADER_ID.

    // 初始化被LOADER_ID标识的加载器。

    getLoaderManager().initLoader(

            LOADER_ID,  // The identifier of the loader to initialize 要初始化的加载器的标识符

            null,       // Arguments for the loader (in this case, none) 加载器的参数(在这种情况下,无)

            this);      // The context of the activity 活动的上下文

 

    // Creates a new cursor adapter to attach to the list view

    // 创建一个新的游标适配器以依附到列表视图

    mCursorAdapter = new SimpleCursorAdapter(

            this,                        // the context of the activity 活动的上下文

            R.layout.detail_list_item,   // the view item containing the detail widgets 包含明细部件的视图条目

            mCursor,                     // the backing cursor 支持游标

            mFromColumns,                // the columns in the cursor that provide the data 提供数据的游标的列

            mToViews,                    // the views in the view item that display the data 显示数据的视图条目中的视图 

            0);                          // flags 标志

 

    // Sets the ListView's backing adapter.

    // 设置ListView的支持适配器

    mRawContactList.setAdapter(mCursorAdapter);

...

@Override

public Loader onCreateLoader(int id, Bundle args) {

 

    /*

     * Sets the columns to retrieve.

     * RAW_CONTACT_ID is included to identify the raw contact associated with the data row.

     * DATA1 contains the first column in the data row (usually the most important one).

     * MIMETYPE indicates the type of data in the data row.

     * 设置要取出的列

     * RAW_CONTACT_ID被包含以标识与该数据行关联的原始电话簿。

     * DATA1包含数据行中的第一列(通常是最重要的列)

     * MIMETYPE指示数据行中的数据的类型。

     */

    String[] projection =

        {

            ContactsContract.Contacts.Entity.RAW_CONTACT_ID,

            ContactsContract.Contacts.Entity.DATA1,

            ContactsContract.Contacts.Entity.MIMETYPE

        };

 

    /*

     * Sorts the retrieved cursor by raw contact id, to keep all data rows for a single raw

     * contact collated together.

     * 根据原始电话簿Id来排序取出的游标,以让一个单一原始电话簿的所有数据行一起对照。

     */

    String sortOrder =

            ContactsContract.Contacts.Entity.RAW_CONTACT_ID +

            " ASC";

 

    /*

     * Returns a new CursorLoader. The arguments are similar to

     * ContentResolver.query(), except for the Context argument, which supplies the location of

     * the ContentResolver to use.

     * 返回一个新的CursorLoader。参数类似于ContentResolver.query(),

     * 除了Context参数,它提供要使用的ContentResolver的位置。

     */

    return new CursorLoader(

            getApplicationContext(),  // The activity's context 活动的上下文

            mContactUri,              // The entity content URI for a single contact 一个电话簿的实体内容URI

            projection,               // The columns to retrieve 要取出的列

            null,                     // Retrieve all the raw contacts and their data rows. 取出所有原始电话簿和它们的数据行

            null,                     //

            sortOrder);               // Sort by the raw contact ID. 根据原始电话簿ID排序

}

 

-------------------------------

 

When the load is finished, LoaderManager invokes a callback to onLoadFinished(). One of the incoming arguments to this method is a Cursor with the results of the query. In your own app, you can get the data from this Cursor to display it or work with it further.

 

当加载完成时,LoaderManager调用一个对onLoadFinished()的回调。传给这个方法的其中一个输入参数是带有该查询结果的一个Cursor。在你自己的应用中,你可以从这个Cursor中获得数据以显示它或进一步处理它。

 

Batch modification

 

批量修改

 

Whenever possible, you should insert, update, and delete data in the Contacts Provider in "batch mode", by creating an ArrayList of ContentProviderOperation objects and calling applyBatch(). Because the Contacts Provider performs all of the operations in an applyBatch() in a single transaction, your modifications will never leave the contacts repository in an inconsistent state. A batch modification also facilitates inserting a raw contact and its detail data at the same time.

 

每当可能时,你应该以“批量模式”在电话簿提供者中插入、更新和删除数据,通过创建一个ContentProviderOperation对象的数组并调用applyBatch()。因为电话簿提供者以一个单一事务在一个applyBatch()中执行所有操作,所以你的修改将从不让电话簿仓库停留在(注:离开?)一个不一致的状态中。一个批量修改还方便在相同时间上插入一个原始电话簿和它的明细数据。

 

-------------------------------

 

Note: To modify a single raw contact, consider sending an intent to the device's contacts application rather than handling the modification in your app. Doing this is described in more detail in the section Retrieval and modification with intents.

 

注意:为了修改一个单一原始电话簿,考虑发送一个意图到设备的电话簿应用程序而非在你的应用中处理修改。在章节使用意图的检索和修改中被更详细地描述这样做。

 

-------------------------------

 

Yield points

 

挂起点

 

A batch modification containing a large number of operations can block other processes, resulting in a bad overall user experience. To organize all the modifications you want to perform in as few separate lists as possible, and at the same time prevent them from blocking the system, you should set yield points for one or more operations. A yield point is a ContentProviderOperation object that has its isYieldAllowed() value set to true. When the Contacts Provider encounters a yield point, it pauses its work to let other processes run and closes the current transaction. When the provider starts again, it continues with the next operation in the ArrayList and starts a new transaction.

 

一个包含大量操作的批量修改可以阻塞其它进程,导致一个不好的整体用户体验。为了组织你想执行的所有修改在一些尽可能少的分离列表中,并且同时阻止它们阻塞系统,你应该为一个或多个操作设置挂起点,一个挂起点是一个ContentProviderOperation对象,它让它的isYieldAllowed()值设置为true。当电话簿提供者遇到一个挂起点时,它暂停它的工作以让其它进程运行并关闭当前事务。当提供者再次开始时,它继续ArrayList中下一个操作并开始一个新的事务。

 

Yield points do result in more than one transaction per call to applyBatch(). Because of this, you should set a yield point for the last operation for a set of related rows. For example, you should set a yield point for the last operation in a set that adds a raw contact rows and its associated data rows, or the last operation for a set of rows related to a single contact.

 

挂起点导致每个对applyBatch()的调用有多于一个事务。因此,你应该为一组相关行的最后操作设置一个挂起点。例如,你应该为一个集合(注:一组行)的最后操作设置一个挂起点,它添加一个原始电话簿行和它的相关数据行,或者是与一个单一电话簿相关的一组行的最后操作。

 

Yield points are also a unit of atomic operation. All accesses between two yield points will either succeed or fail as a single unit. If you don't set any yield points, the smallest atomic operation is the entire batch of operations. If you do use yield points, you prevent operations from degrading system performance, while at the same time ensuring that a subset of operations is atomic.

 

挂起点还是一个原始操作单位。在两个挂起点之间的所有访问将作为一个单一单位要么成功要么失败。如果你不设置任意挂起点,最小的原子操作是整个批量的操作。如果你使用挂起点,你阻止操作降低系统性能,然而同时确保操作的一个子集是原子的。

 

Modification back references

 

修改的向后引用

 

When you're inserting a new raw contact row and its associated data rows as a set of ContentProviderOperation objects, you have to link the data rows to the raw contact row by inserting the raw contact's _ID value as the RAW_CONTACT_ID value. However, this value isn't available when you're creating the ContentProviderOperation for the data row, because you haven't yet applied the ContentProviderOperation for the raw contact row. To work around this, the ContentProviderOperation.Builder class has the method withValueBackReference(). This method allows you to insert or modify a column with the result of a previous operation.

 

当你正在插入一个新的原始电话簿行和它的相关数据行作为一组ContentProviderOperation对象时,你不得不通过插入原始电话簿的_ID值作为RAW_CONTACT_ID值,链接数据行到原始电话簿行。然而,这个值不可用,当你正在为数据行创建ContentProviderOperation时,因为你不曾对原始电话簿行应用ContentProviderOperation。为了绕过它,ContentProviderOperation.Builder类拥有方法withValueBackReference()。这个方法允许你用前一次操作的结果插入或修改一个列。

 

The withValueBackReference() method has two arguments:

 

withValueBackReference()方法拥有两个参数:

 

key

 

The key of a key-value pair. The value of this argument should be the name of a column in the table that you're modifying.

 

一个键值对的键。这个参数的值应该是你正在修改的表中的一个列的名称。

 

previousResult

 

The 0-based index of a value in the array of ContentProviderResult objects from applyBatch(). As the batch operations are applied, the result of each operation is stored in an intermediate array of results. The previousResult value is the index of one of these results, which is retrieved and stored with the key value. This allows you to insert a new raw contact record and get back its _ID value, then make a "back reference" to the value when you add a ContactsContract.Data row.

 

来自applyBatch()的ContentProviderResult对象数组中一个值的0开始索引。当批量操作被应用时,每个操作的结果被存储在一个中间的结果数组中。previousResult值是这些结果中其中一个的索引,它用该键值来取出和存储。这允许你插入一个新的原始电话簿记录并取回它的_ID值,然后制造一个指向该值的“向后引用”,当你添加ContactsContract.Data行时。

 

The entire result array is created when you first call applyBatch(), with a size equal to the size of the ArrayList of ContentProviderOperation objects you provide. However, all the elements in the result array are set to null, and if you try to do a back reference to a result for an operation that hasn't yet been applied, withValueBackReference() throws an Exception.

 

整个结果数组被创建,当你最先调用applyBatch()时,使用一个大小等于你提供的ContentProviderOperation对象的ArrayList的大小。然而,结果数组中的所有元素被设置为null,而且如果你尝试为一个不曾被应用的操作执行指向一个结果的一个向后引用,withValueBackReference()会抛出一个Exception。

 

The following snippets show how to insert a new raw contact and data in batch. They includes code that establishes a yield point and uses a back reference. The snippets are an expanded version of the createContacEntry() method, which is part of the ContactAdder class in the Contact Manager sample application.

 

以下代码片段展示如何批量插入一个新的原始电话簿和数据。它们包含建立一个挂起点和使用一个向后引用的代码。代码片段是createContacEntry()方法的一个扩展版本,而那个方法则是电话簿管理器示例应用程序中ContactAdder类的一部分。

 

The first snippet retrieves contact data from the UI. At this point, the user has already selected the account for which the new raw contact should be added.

 

第一个代码片段从用户界面中取出电话簿数据。在这个时间点上,用户已经选中账户,新的原始电话簿应该要为它而被添加。

 

-------------------------------

 

// Creates a contact entry from the current UI values, using the currently-selected account.

// 从当前用户界面值中创建一个电话簿记录,使用当前选择的账户。

protected void createContactEntry() {

    /*

     * Gets values from the UI

     * 从用户界面中获得值

     */

    String name = mContactNameEditText.getText().toString();

    String phone = mContactPhoneEditText.getText().toString();

    String email = mContactEmailEditText.getText().toString();

 

    int phoneType = mContactPhoneTypes.get(

            mContactPhoneTypeSpinner.getSelectedItemPosition());

 

    int emailType = mContactEmailTypes.get(

            mContactEmailTypeSpinner.getSelectedItemPosition());

 

-------------------------------

 

The next snippet creates an operation to insert the raw contact row into the ContactsContract.RawContacts table:

 

下一个代码片段创建一个操作以插入原始电话簿行进ContactsContract.RawContacts表中:

 

-------------------------------

 

    /*

     * Prepares the batch operation for inserting a new raw contact and its data. Even if

     * the Contacts Provider does not have any data for this person, you can't add a Contact,

     * only a raw contact. The Contacts Provider will then add a Contact automatically.

     * 准备插入一个新的原始电话簿和它的数据的批量操作。

     * 即便电话簿提供者没有这个人的任意数据,你无法添加一个电话簿,只是一个原始电话簿。

     * 然后电话簿提供者将自动地添加一个电话簿。

     */

 

     // Creates a new array of ContentProviderOperation objects.

     // 创建一个新的ContentProviderOperation对象数组

    ArrayList ops =

            new ArrayList();

 

    /*

     * Creates a new raw contact with its account type (server type) and account name

     * (user's account). Remember that the display name is not stored in this row, but in a

     * StructuredName data row. No other data is required.

     * 用它的账户类型(服务器类型)和账户名称(用户的账户)创建一个新的原始电话簿。

     * 记住显示名称不被存储在这个行中,而是在一个StructuredName数据行中。

     * 不需要其它数据。

     */

    ContentProviderOperation.Builder op =

            ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)

            .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType())

            .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName());

 

    // Builds the operation and adds it to the array of operations

    // 构建操作和添加它到操作数组

    ops.add(op.build());

 

-------------------------------

 

Next, the code creates data rows for the display name, phone, and email rows.

 

接下来,代码为显示名称、电话、和电子邮件行创建数据行。

 

Each operation builder object uses withValueBackReference() to get the RAW_CONTACT_ID. The reference points back to the ContentProviderResult object from the first operation, which adds the raw contact row and returns its new _ID value. As a result, each data row is automatically linked by its RAW_CONTACT_ID to the new ContactsContract.RawContacts row to which it belongs.

 

每个操作构建器对象使用withValueBackReference()以获得RAW_CONTACT_ID。该引用向后指向来自第一个操作的ContentProviderResult对象,它添加原始电话簿行并返回它的新的_ID值。作为一个结果,每个数据行被它的RAW_CONTACT_ID自动地链接到新的它所属的ContactsContract.RawContacts行。

 

The ContentProviderOperation.Builder object that adds the email row is flagged with withYieldAllowed(), which sets a yield point:

 

添加电子邮箱行的ContentProviderOperation.Builder对象使用withYieldAllowed()来被标示,它设置一个挂起点。

 

-------------------------------

 

    // Creates the display name for the new raw contact, as a StructuredName data row.

    // 创建新的原始电话簿的显示名称,作为一个StructuredName数据行

    op =

            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)

            /*

             * withValueBackReference sets the value of the first argument to the value of

             * the ContentProviderResult indexed by the second argument. In this particular

             * call, the raw contact ID column of the StructuredName data row is set to the

             * value of the result returned by the first operation, which is the one that

             * actually adds the raw contact row.

             * withValueBackReference设置第一参数的值为被第二参数索引的ContentProviderResult的值

             * 在这个特殊调用中,StructuredName数据行的原始电话簿ID列被设置为被第一操作返回的结果的值,

             * 它是实际添加原始电话簿行的操作。

             */

            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

 

            // Sets the data row's MIME type to StructuredName

            // 设置数据行的MIME类型为StructuredName

            .withValue(ContactsContract.Data.MIMETYPE,

                    ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)

 

            // Sets the data row's display name to the name in the UI.

            // 设置数据行的显示名称为用户界面中的名称。

            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name);

 

    // Builds the operation and adds it to the array of operations

    // 构建操作并添加它到操作数组

    ops.add(op.build());

 

    // Inserts the specified phone number and type as a Phone data row

    // 插入指定电话号码和类型作为一个Phone数据行

    op =

            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)

            /*

             * Sets the value of the raw contact id column to the new raw contact ID returned

             * by the first operation in the batch.

             * 设置原始电话簿id列的值为被批处理中第一操作返回的新的原始电话簿ID。

             */

            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

 

            // Sets the data row's MIME type to Phone

            // 设置数据行的MIME类型为电话

            .withValue(ContactsContract.Data.MIMETYPE,

                    ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)

 

            // Sets the phone number and type

            // 设置电话号码和类型

            .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)

            .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType);

 

    // Builds the operation and adds it to the array of operations

    // 构建操作并添加它到操作数组

    ops.add(op.build());

 

    // Inserts the specified email and type as a Phone data row

    // 插入指定电子邮件和类型作为一个Phone数据行

    op =

            ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)

            /*

             * Sets the value of the raw contact id column to the new raw contact ID returned

             * by the first operation in the batch.

             * 设置原始电话簿id列的值为被批处理中第一操作返回的新的原始电话簿ID。

             */

            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)

 

            // Sets the data row's MIME type to Email

            // 设置数据行的MIME类型为电子邮件

            .withValue(ContactsContract.Data.MIMETYPE,

                    ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)

 

            // Sets the email address and type

            // 设置电子邮箱地址和类型

            .withValue(ContactsContract.CommonDataKinds.Email.ADDRESS, email)

            .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType);

 

    /*

     * Demonstrates a yield point. At the end of this insert, the batch operation's thread

     * will yield priority to other threads. Use after every set of operations that affect a

     * single contact, to avoid degrading performance.

     * 演示一个挂起点。在这个插入的最后,批量操作的线程将让出优先级给其它线程。

     * 在影响一个电议电话簿的每个集合的操作后使用,以避免降低性能。

     */

    op.withYieldAllowed(true);

 

    // Builds the operation and adds it to the array of operations

    // 构建操作并添加它到操作数组

    ops.add(op.build());

 

-------------------------------

 

The last snippet shows the call to applyBatch() that inserts the new raw contact and data rows.

 

最后的代码片段展示对applyBatch()的调用,它插入新的原始电话簿和数据行。

 

-------------------------------

 

    // Ask the Contacts Provider to create a new contact

    // 叫电话簿提供者创建一个新的电话簿

    Log.d(TAG,"Selected account: " + mSelectedAccount.getName() + " (" +

            mSelectedAccount.getType() + ")");

    Log.d(TAG,"Creating contact: " + name);

 

    /*

     * Applies the array of ContentProviderOperation objects in batch. The results are

     * discarded.

     * 在批处理中应用ContentProviderOperation对象的数组。

     * 结果被丢弃。

     */

    try {

 

            getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);

    } catch (Exception e) {

 

            // Display a warning

            // 显示一个警告

            Context ctx = getApplicationContext();

 

            CharSequence txt = getString(R.string.contactCreationFailure);

            int duration = Toast.LENGTH_SHORT;

            Toast toast = Toast.makeText(ctx, txt, duration);

            toast.show();

 

            // Log exception

            // 记录异常

            Log.e(TAG, "Exception encountered while inserting contact: " + e);

    }

}

 

-------------------------------

 

Batch operations also allow you to implement optimistic concurrency control, a method of applying modification transactions without having to lock the underlying repository. To use this method, you apply the transaction and then check for other modifications that may have been made at the same time. If you find an inconsistent modification has occurred, you roll back your transaction and retry it.

 

批量操作还允许你实现乐观并发控制,一种应用修改事务而不必锁定底层仓库的方法。为了使用这个方法,你应用事务然后检查其它可能已经同时作出的修改。如果你发现一个不一致的修改已经发生,你回滚你的事务并重试它。

 

Optimistic concurrency control is useful for a mobile device, where there's only one user at a time, and simultaneous accesses to a data repository are rare. Because locking isn't used, no time is wasted on setting locks or waiting for other transactions to release their locks.

 

乐观并发控制对于一个移动设备来说是有用的,那里在一个时候只存在一个用户,而且对于一个数据仓库的同时访问是罕见的。因为锁定不被使用,所以没有消耗时间在设置锁定或等待其它事务来释放它们的锁。

 

To use optimistic concurrency control while updating a single ContactsContract.RawContacts row, follow these steps:

 

为了在更新一个单一ContactsContract.RawContacts行时使用乐观并发控制,请遵循这些步骤:

 

1. Retrieve the raw contact's VERSION column along with the other data you retrieve.

 

1. 取出原始电话簿的VERSION列伴随你取出的其它数据。

 

2. Create a ContentProviderOperation.Builder object suitable for enforcing a constraint, using the method newAssertQuery(Uri). For the content URI, use RawContacts.CONTENT_URI with the raw contact's _ID appended to it.

 

2. 创建一个适合实施一个约束的ContentProviderOperation.Builder对象,通过使用方法newAssertQuery(Uri)。对于内容URI,请使用RawContacts.CONTENT_URI,让原始电话簿的_ID尾加到它。

 

3. For the ContentProviderOperation.Builder object, call withValue() to compare the VERSION column to the version number you just retrieved.

 

3. 对于ContentProviderOperation.Builder对象,调用withValue()来比较VERSION列和你正取出的版本数。

 

4. For the same ContentProviderOperation.Builder, call withExpectedCount() to ensure that only one row is tested by this assertion.

 

4. 对于相同的ContentProviderOperation.Builder,请调用withExpectedCount()以确保只有一行被这个诊断测试。

 

5. Call build() to create the ContentProviderOperation object, then add this object as the first object in the ArrayList that you pass to applyBatch().

 

5. 调用build()来创建ContentProviderOperation对象,然后添加这个对象作为你传递给applyBatch()的ArrayList里的第一个对象。

 

6. Apply the batch transaction.

 

6. 应用批量事务。

 

If the raw contact row is updated by another operation between the time you read the row and the time you attempt to modify it, the "assert" ContentProviderOperation will fail, and the entire batch of operations will be backed out. You can then choose to retry the batch or take some other action.

 

如果原始电话簿行被另一个操作更新,在你读取该行的时候和你尝试修改它的时候之间,那么“诊断”ContentProviderOperation将失败,并且整个批量操作将被放弃。然后,你可以选择重新尝试批处理或采取其它动作。

 

The following snippet demonstrates how to create an "assert" ContentProviderOperation after querying for a single raw contact using a CursorLoader:

 

以下代码片段演示如何在使用一个CursorLoader查询一个单一原始电话簿后创建一个“诊断”ContentProviderOperation。

 

-------------------------------

 

/*

 * The application uses CursorLoader to query the raw contacts table. The system calls this method

 * when the load is finished.

 * 应用程序使用CursorLoader以查询原始电话簿表。

 * 当加载完成时系统调用这个方法。

 */

public void onLoadFinished(Loader loader, Cursor cursor) {

 

    // Gets the raw contact's _ID and VERSION values

    // 获得原始电话簿的_ID和VERSION值

    mRawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID));

    mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION));

}

 

...

 

// Sets up a Uri for the assert operation

// 为诊断操作配置一个Uri

Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, mRawContactID);

 

// Creates a builder for the assert operation

// 为诊断操作创建一个构造器

ContentProviderOperation.Builder assertOp = ContentProviderOperation.netAssertQuery(rawContactUri);

 

// Adds the assertions to the assert operation: checks the version and count of rows tested

// 添加诊断到诊断操作:检查版本和被测试的行数

assertOp.withValue(SyncColumns.VERSION, mVersion);

assertOp.withExpectedCount(1);

 

// Creates an ArrayList to hold the ContentProviderOperation objects

// 创建一个ArrayList以装载ContentProviderOperation对象

ArrayList ops = new ArrayList;

 

ops.add(assertOp.build());

 

// You would add the rest of your batch operations to "ops" here

// 你将添加你余下的批处理操作到这里的"ops”

 

...

 

// Applies the batch. If the assert fails, an Exception is thrown

// 应用批处理。如果诊断失败,抛出一个Exception

try

    {

        ContentProviderResult[] results =

                getContentResolver().applyBatch(AUTHORITY, ops);

 

    } catch (OperationApplicationException e) {

 

        // Actions you want to take if the assert operation fails go here

        // 如果诊断操作失败,你想采取的动作放在这里

    }

 

-------------------------------

 

Retrieval and modification with intents

 

使用意图的检索与修改

 

Sending an intent to the device's contacts application allows you to access the Contacts Provider indirectly. The intent starts the device's contacts application UI, in which users can do contacts-related work. With this type of access, users can:

 

发送一个意图给设备的电话簿应用程序允许你直接地访问电话簿提供者。意图启动设备的电话簿应用程序用户界面,其中用户可以执行电话簿相关的工作。通过使用此类访问,用户可以。

 

* Pick a contact from a list and have it returned to your app for further work.

 

* 从一个列表中拾取一个电话簿并让它返回给你的应用供进一步工作使用。

 

* Edit an existing contact's data.

 

* 编辑一个现存电话簿的数据。

 

* Insert a new raw contact for any of their accounts.

 

* 为他们的任意账户插入一个新的原始电话簿。

 

* Delete a contact or contacts data.

 

* 删除一个或多个电话簿数据。

 

If the user is inserting or updating data, you can collect the data first and send it as part of the intent.

 

如果用户正在插入或更新数据,你可以首先收集数据并发送它作为意图的一部分。

 

When you use intents to access the Contacts Provider via the device's contacts application, you don't have to write your own UI or code for accessing the provider. You also don't have to request permission to read or write to the provider. The device's contacts application can delegate read permission for a contact to you, and because you're making modifications to the provider through another application, you don't have to have write permissions.

 

当你使用意图通过设备的电话簿应用程序访问电话簿提供者时,你不必编写你自己的用户界面或代码来访问提供者。你还不必请求权限来读取或写入到提供者。设备的电话簿应用程序可以委托一个电话簿的读取权限给你,而且因为你正在通过另一个应用程序作出对提供者的修改,你不必拥有写入权限。

 

The general process of sending an intent to access a provider is described in detail in the Content Provider Basics guide in the section "Data access via intents." The action, MIME type, and data values you use for the available tasks are summarized in Table 4, while the extras values you can use with putExtra() are listed in the reference documentation for ContactsContract.Intents.Insert:

 

发送一个意图以访问一个提供者的一般权限被更详细地描述在内容提供者基础指引的章节“通过意图的数据访问”中。你为可用的任务而使用的动作,MIME类型,以及数据值被总结在表4中,而你可以用于putExtra()的额外值被列举在ContactsContract.Intents.Insert的参考文档中:

 

Table 4. Contacts Provider Intents.

 

表4. 电话簿提供者意图。

 

-------------------------------

 

Task ActionData MIME typeNotes

 

任务 动作 数据 MIME类型 注意事项

 

Pick a contact from a list

ACTION_PICK 

One of:

 

从一个列表中拾取一个电话簿 

ACTION_PICK 

其中之一:

 

* Contacts.CONTENT_URI, which displays a list of contacts.

 

* Contacts.CONTENT_URI,它显示一个电话簿列表

 

* Phone.CONTENT_URI, which displays a list of phone numbers for a raw contact.

 

* Phone.CONTENT_URI,它显示一个原始电话簿的一个电话号码列表。

 

* StructuredPostal.CONTENT_URI, which displays a list of postal addresses for a raw contact.

 

* StructuredPostal.CONTENT_URI,它显示一个原始电话簿的一个邮政地址列表。

 

* Email.CONTENT_URI, which displays a list of email addresses for a raw contact.

 

* Email.CONTENT_URI,它显示一个原始电话簿的一个电子邮箱地址列表。

 

Not used 

Displays a list of raw contacts or a list of data from a raw contact, depending on the content URI type you supply.

 

未使用 

显示一个原始电话簿列表或来自一个原始电话簿的一个数据列表,依赖于你提供的内容URI类型。

 

Call startActivityForResult(), which returns the content URI of the selected row. The form of the URI is the table's content URI with the row's LOOKUP_ID appended to it. The device's contacts app delegates read and write permissions to this content URI for the life of your activity. See the Content Provider Basics guide for more details.

 

调用startActivityForResult(),它返回选中行的内容URI。URI的格式是表的内容URI带尾加到它的该行的LOOKUP_ID。设备的电话簿应用在你的活动的生命周期内委托读写权限给这个内容URI。见内容提供者基础指引以获得更多细节。

 

Insert a new raw contact

Insert.ACTION

N/A

RawContacts.CONTENT_TYPE, MIME type for a set of raw contacts. 

Displays the device's contacts application's Add Contact screen. The extras values you add to the intent are displayed. If sent with startActivityForResult(), the content URI of the newly-added raw contact is passed back to your activity's onActivityResult() callback method in the Intent argument, in the "data" field. To get the value, call getData().

 

插入一个新的原始电话簿 

Insert.ACTION 

不可用 

RawContacts.CONTENT_TYPE,一组原始电话簿的MIME类型。

显示设备的电话簿应用程序的添加电话簿屏幕。你添加到意图的额外值被显示。如果使用startActivityForResult()发送,那么新添加的原始电话簿的内容URI被传递回你的活动的onActivityResult()回调方法的Intent参数中,在"data"域内。为了获得该值,请调用getData()。

 

Edit a contact

ACTION_EDIT

CONTENT_LOOKUP_URI for the contact. The editor activity will allow the user to edit any of the data associated with this contact.

Contacts.CONTENT_ITEM_TYPE, a single contact. 

Displays the Edit Contact screen in the contacts application. The extras values you add to the intent are displayed. When the user clicks Done to save the edits, your activity returns to the foreground.

 

编辑一个电话簿 

ACTION_EDIT 

电话簿的CONTENT_LOOKUP_URI。实际上编辑器将允许用户编辑与这个电话簿关联的任意数据。 

Contacts.CONTENT_ITEM_TYPE,一个单一电话簿 

在电话簿应用程序中显示编辑电话簿屏幕。你添加到意图的额外数据值被显示。当用户点击完成并保存编辑时,你的活动返回到前台。

 

Display a picker that can also add data.

ACTION_INSERT_OR_EDIT 

N/A

CONTENT_ITEM_TYPE 

This intent always displays the contacts app's picker screen. The user can either pick a contact to edit, or add a new contact. Either the edit or the add screen appears, depending on the user's choice, and the extras data you pass in the intent is displayed. If your app displays contact data such as an email or phone number, use this intent to allow the user to add the data to an existing contact. contact,

 

显示一个还可以添加数据的拾取器。 

ACTION_INSERT_OR_EDIT 

不可用 

CONTENT_ITEM_TYPE 

这个意图总是显示电话簿应用的拾取器屏幕。用户可以拾取一个要编辑的电话簿,或者添加一个新的电话簿。不管是编辑还是添加屏幕出现,依赖于用户的选择,以及你在意图中传递的额外数据被显示。如果你的应用显示电话簿数据诸如一个电子邮件或电话号码,使用这个意图允许用户添加数据到一个现存电话簿。电话簿(注:此处疑有缺失)

 

-------------------------------

 

Note: There's no need to send a name value in this intent's extras, because the user always picks an existing name or adds a new one. Moreover, if you send a name, and the user chooses to do an edit, the contacts app will display the name you send, overwriting the previous value. If the user doesn't notice this and saves the edit, the old value is lost.

 

注意:没有必要在这个意图的额外数据中发送一个名称值,因为用户总是拾取一个现存名称或添加一个新名称。再者,如果你发送一个名称,而用户选择做一个编辑,电话簿应用将显示你发送的名称,覆写前一个值。如果用户没注意到它且保存编辑,那么旧的值丢失。

 

-------------------------------

 

The device's contacts app doesn't allow you to delete a raw contact or any of its data with an intent. Instead, to delete a raw contact, use ContentResolver.delete() or ContentProviderOperation.newDelete().

 

设备的电话簿应用不允许你使用一个意图删除一个原始电话簿或它的任意数据。相反,为了删除一个原始电话簿,请使用ContentResolver.delete()或ContentProviderOperation.newDelete()。

 

The following snippet shows how to construct and send an intent that inserts a new raw contact and data:

 

以下代码片段展示如何构造并发送一个意图,它插入一个新的原始电话簿和数据:

 

-------------------------------

 

// Gets values from the UI

// 从用户界面中获得值

String name = mContactNameEditText.getText().toString();

String phone = mContactPhoneEditText.getText().toString();

String email = mContactEmailEditText.getText().toString();

 

String company = mCompanyName.getText().toString();

String jobtitle = mJobTitle.getText().toString();

 

// Creates a new intent for sending to the device's contacts application

// 创建一个新的意图以便发送到设备的电话簿应用程序。

Intent insertIntent = new Intent(ContactsContract.Intents.Insert.ACTION);

 

// Sets the MIME type to the one expected by the insertion activity

// 设置MIME类型到插入活动所期待的电话簿

insertIntent.setType(ContactsContract.RawContacts.CONTENT_TYPE);

 

// Sets the new contact name

// 设置新的电话簿名称

insertIntent.putExtra(ContactsContract.Intents.Insert.NAME, name);

 

// Sets the new company and job title

// 设置新的公司和工作标题

insertIntent.putExtra(ContactsContract.Intents.Insert.COMPANY, company);

insertIntent.putExtra(ContactsContract.Intents.Insert.JOB_TITLE, jobtitle);

 

/*

 * Demonstrates adding data rows as an array list associated with the DATA key

 * 演示添加数据行作为一个与DATA键关联的数组列表

 */

 

// Defines an array list to contain the ContentValues objects for each row

// 定义一个数组列表以包含每一行的ContentValues对象

ArrayList contactData = new ArrayList();

 

 

/*

 * Defines the raw contact row

 * 定义原始电话簿行

 */

 

// Sets up the row as a ContentValues object

// 配置行作为一个ContentValues对象

ContentValues rawContactRow = new ContentValues();

 

// Adds the account type and name to the row

// 添加账户类型和名称到行

rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType());

rawContactRow.put(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName());

 

// Adds the row to the array

// 添加行到数组

contactData.add(rawContactRow);

 

/*

 * Sets up the phone number data row

 * 配置电话号码数据行

 */

 

// Sets up the row as a ContentValues object

// 配置该行作为一个ContentValues对象

ContentValues phoneRow = new ContentValues();

 

// Specifies the MIME type for this data row (all data rows must be marked by their type)

// 为这个数据行指定MIME类型(所有数据行必须被它们的类型标记)

phoneRow.put(

        ContactsContract.Data.MIMETYPE,

        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE

);

 

// Adds the phone number and its type to the row

// 添加电话号码和它的类型到该行

phoneRow.put(ContactsContract.CommonDataKinds.Phone.NUMBER, phone);

 

// Adds the row to the array

// 添加行到数组

contactData.add(phoneRow);

 

/*

 * Sets up the email data row

 * 配置电子邮件数据行

 */

 

// Sets up the row as a ContentValues object

// 配置该行作为一个ContentValues值

ContentValues emailRow = new ContentValues();

 

// Specifies the MIME type for this data row (all data rows must be marked by their type)

// 为这个数据行指定MIME类型(所有数据行必须被它们的类型标记)

emailRow.put(

        ContactsContract.Data.MIMETYPE,

        ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE

);

 

// Adds the email address and its type to the row

// 添加电子邮件地址和它的类型到该行

emailRow.put(ContactsContract.CommonDataKinds.Email.ADDRESS, email);

 

// Adds the row to the array

// 添加该行到数组

contactData.add(emailRow);

 

/*

 * Adds the array to the intent's extras. It must be a parcelable object in order to

 * travel between processes. The device's contacts app expects its key to be

 * Intents.Insert.DATA

 * 添加该数组到意图的额外数据。它必须是一个可封包对象,以便在进程之间通行。

 * 设备的电话簿应用期待它的键成为Intents.Insert.DATA。

 */

insertIntent.putParcelableArrayListExtra(ContactsContract.Intents.Insert.DATA, contactData);

 

// Send out the intent to start the device's contacts app in its add contact activity.

// 在它的添加电话簿活动中发送出意图以启动设备的电话簿应用

startActivity(insertIntent);

 

-------------------------------

 

Data integrity

 

数据完整性

 

Because the contacts repository contains important and sensitive data that users expect to be correct and up-to-date, the Contacts Provider has well-defined rules for data integrity. It's your responsibility to conform to these rules when you modify contacts data. The important rules are listed here:

 

因为电话簿仓库包含重要的和敏感的数据,用户期待被更正和升级,所以电话簿提供者对数据完整性拥有良好定义的规则。这是你的责任遵守这些规则,当你修改电话簿数据时。重要规则被列举在这里:

 

Always add a ContactsContract.CommonDataKinds.StructuredName row for every ContactsContract.RawContacts row you add.

 

总是为你添加的每一个ContactsContract.RawContacts行添加一个ContactsContract.CommonDataKinds.StructuredName行。

 

A ContactsContract.RawContacts row without a ContactsContract.CommonDataKinds.StructuredName row in the ContactsContract.Data table may cause problems during aggregation.

 

在ContactsContract.Data表中一个不带ContactsContract.CommonDataKinds.StructuredName行的ContactsContract.RawContacts行在聚集期间可能导致一些问题。

 

Always link new ContactsContract.Data rows to their parent ContactsContract.RawContacts row.

 

总是链接新的ContactsContract.Data行到它们的父ContactsContract.RawContacts行。

 

A ContactsContract.Data row that isn't linked to a ContactsContract.RawContacts won't be visible in the device's contacts application, and it might cause problems with sync adapters.

 

一个不链接到一个ContactsContract.RawContacts的ContactsContract.Data行将在设备的电话簿应用程序中不可见,而且使用同步适配器可能导致一些问题。

 

Change data only for those raw contacts that you own.

 

只为你所拥有的那些原始电话簿而改变数据。

 

Remember that the Contacts Provider is usually managing data from several different account types/online services. You need to ensure that your application only modifies or deletes data for rows that belong to you, and that it only inserts data with an account type and name that you control.

 

记住电话簿提供者常常正在管理来自几个不同账户类型/在线服务的数据。你需要确保你的应用程序只修改或删除属于你的行的数据,并且它只用你控制的一个账户类型和名称名称插入数据。

 

Always use the constants defined in ContactsContract and its subclasses for authorities, content URIs, URI paths, column names, MIME types, and TYPE values.

 

总是使用定义在ContactsContract和它的子类中的常量以获得权力、内容URI、URI路径、列名、MIME类型和TYPE值。

 

Using these constants helps you to avoid errors. You'll also be notified with compiler warnings if any of the constants is deprecated.

 

使用这些常量有助于你避免错误。你还将被编译器警告通知,如果那些常量中任意是被废弃的。

 

Custom data rows

 

自定义数据行

 

By creating and using your own custom MIME types, you can insert, edit, delete, and retrieve your own data rows in the ContactsContract.Data table. Your rows are limited to using the column defined in ContactsContract.DataColumns, although you can map your own type-specific column names to the default column names. In the device's contacts application, the data for your rows is displayed but can't be edited or deleted, and users can't add additional data. To allow users to modify your custom data rows, you must provide an editor activity in your own application.

 

通过创建和使用你自己的自定义MIME类型,你可以插入、编辑、删除,和取出在ContactsContract.Data表中你自己的数据行。你的行被限制只能使用定义在ContactsContract.DataColumns中的列,虽然你可以映射你自己的类型特定列名到默认的列名。在设备的电话簿应用程序中,你的行的数据被显示,但不能被编辑或删除,而且用户不能添加额外数据。为了允许用户修改你的自定义数据行,你必须在你自己的应用程序中提供一个编辑器活动。

 

To display your custom data, provide a contacts.xml file containing a element and one or more of its child elements. This is described in more detail in the section element.

 

为了显示你的自定义数据,提供一个包含一个元素和它的一个或多个子元素的 contacts.xml文件。这被更详细地描述在章节元素中。

 

To learn more about custom MIME types, read the Creating a Content Provider guide.

 

为了学习更多关于自定义MIME类型的内容,请阅读创建一个内容提供者指引。

 

-------------------------------

 

Contacts Provider Sync Adapters

 

电话簿提供者同步适配器

 

The Contacts Provider is specifically designed for handling synchronization of contacts data between a device and an online service. This allows users to download existing data to a new device and upload existing data to a new account. Synchronization also ensures that users have the latest data at hand, regardless of the source of additions and changes. Another advantage of synchronization is that it makes contacts data available even when the device is not connected to the network.

 

电话簿提供者为处理一个设备和一个在线服务之间的电话簿数据同步而被特殊化地设计。这允许用户下载现存数据到一个新的设备并上传现存数据给一个新的账户。同步还确保用户手上拥有最新数据,不管添加和改变的源是什么。同步的另一个好处是,它使电话簿数据可用,即便当设备未连接到网络。

 

Although you can implement synchronization in a variety of ways, the Android system provides a plug-in synchronization framework that automates the following tasks:

 

虽然你可以以不同的方式实现同步,但Android系统提供一个自动化以下任务的插件式同步框架。

 

* Checking network availability.

 

* 检查网络可用性

 

* Scheduling and executing synchronization, based on user preferences.

 

* 计划和执行同步,基于用户喜好。

 

* Restarting synchronizations that have stopped.

 

* 重启已经停止的同步。

 

To use this framework, you supply a sync adapter plug-in. Each sync adapter is unique to a service and content provider, but can handle multiple account names for the same service. The framework also allows multiple sync adapters for the same service and provider.

 

为了使用这个框架,你提供一个同步适配器插件。每个同步适配器对于一个服务和内容提供者是唯一的,但可以为相同服务处理多个账户名称。框架还允许用于相同服务和提供者的多个同步适配器。

 

Sync adapter classes and files

 

同步适配器类和文件

 

You implement a sync adapter as a subclass of AbstractThreadedSyncAdapter and install it as part of an Android application. The system learns about the sync adapter from elements in your application manifest, and from a special XML file pointed to by the manifest. The XML file defines the account type for the online service and the authority for the content provider, which together uniquely identify the adapter. The sync adapter does not become active until the user adds an account for the sync adapter's account type and enables synchronization for the content provider the sync adapter syncs with. At that point, the system starts managing the adapter, calling it as necessary to synchronize between the content provider and the server.

 

你实现一个同步适配器作为AbstractThreadedSyncAdapter的一个子类并安装它作为一个Android应用程序的一部分。系统从你的应用程序清单中的元素,以及从被清单指向的特定XML中了解同步适配器。XML文件定义在线服务的账户类型和内容提供者的权力,它们一起唯一地标识适配器。同步适配器不变成激活的,直至用户添加同步适配器类型的一个账户并为同步适配器同步的内容提供者而使能认证。在那个时间点上,系统开始管理适配器,当需要时调用它以在内容提供者和服务器之间同步。

 

-------------------------------

 

Note: Using an account type as part of the sync adapter's identification allows the system to detect and group together sync adapters that access different services from the same organization. For example, sync adapters for Google online services all have the same account type com.google. When users add a Google account to their devices, all of the installed sync adapters for Google services are listed together; each sync adapter listed syncs with a different content provider on the device.

 

注意:使用一个账户类型作为同步适配器的标识的一部分,这允许系统一起检测和分组访问来自同一组织不同服务的同步适配器。例如,Google在线服务的同步适配器都拥有相同的账户类型com.google。当用户添加一个Google账户给它们的设备时,Google服务的所有已安装同步适配器被列举在一起;被列举的每个适配器使用设备上不同的内容提供者来同步。

 

-------------------------------

 

Because most services require users to verify their identity before accessing data, the Android system offers an authentication framework that is similar to, and often used in conjunction with, the sync adapter framework. The authentication framework uses plug-in authenticators that are subclasses of AbstractAccountAuthenticator. An authenticator verifies the user's identity in the following steps:

 

因为大多数服务要求用户在访问数据前验证他们的身份,所以Android系统提供一个认证框架,它类似于,且常常一起使用,同步适配器框架。认证框架使用作为AbstractAccountAuthenticator子类的插件式认证器,一个认证器用以下步骤验证用户的身份:

 

1. Collects the user's name, password or similar information (the user's credentials).

 

1. 收集用户名、密码或相似信息(用户的证书)。

 

2. Sends the credentials to the service

 

2. 发送证书到服务

 

3. Examines the service's reply.

 

3. 检查服务的回复。

 

If the service accepts the credentials, the authenticator can store the credentials for later use. Because of the plug-in authenticator framework, the AccountManager can provide access to any authtokens an authenticator supports and chooses to expose, such as OAuth2 authtokens.

 

如果服务接受证书,那么认证器可以存储证书供以后使用。因为插件式认证器框架,AccountManager可以提供访问权给一个认证器支持的任意认证令牌并选择暴露,诸如OAuth2认证令牌。

 

Although authentication is not required, most contacts services use it. However, you're not required to use the Android authentication framework to do authentication.

 

虽然认证不是必需的,但大多数电话簿服务使用它。然而,你并不必须使用Android认证框架来做认证。

 

Sync adapter implementation

 

同步适配器实现

 

To implement a sync adapter for the Contacts Provider, you start by creating an Android application that contains the following:

 

为了为电话簿实现一个同步适配器,你通过创建一个包含以下内容的Android应用程序来开始:

 

A Service component that responds to requests from the system to bind to the sync adapter.

 

一个Service组件,它响应来自系统的请求以绑定到同步适配器。

 

When the system wants to run a synchronization, it calls the service's onBind() method to get an IBinder for the sync adapter. This allows the system to do cross-process calls to the adapter's methods.

 

当系统想运行一次同步时,它调用服务的onBind()方法来为同步适配器获得一个IBinder。这允许系统执行对该适配器的方法的跨进程调用。

 

In the Sample Sync Adapter sample app, the class name of this service is com.example.android.samplesync.syncadapter.SyncService.

 

在示例同步适配器的示例应用中,这个服务的类名是com.example.android.samplesync.syncadapter.SyncService。

 

The actual sync adapter, implemented as a concrete subclass of AbstractThreadedSyncAdapter.

 

实际的同步适配器,被实现作为AbstractThreadedSyncAdapter的一个具体子类。

 

This class does the work of downloading data from the server, uploading data from the device, and resolving conflicts. The main work of the adapter is done in the method onPerformSync(). This class must be instantiated as a singleton.

 

这个类执行从服务器中下载数据,从设备中上传数据,以及解析冲突的工作。适配器的主要工作在方法onPerformSync()中执行。这个类必须作为一个单实例被实例化。

 

In the Sample Sync Adapter sample app, the sync adapter is defined in the class com.example.android.samplesync.syncadapter.SyncAdapter.

 

在示例同步适配器的示例应用里,同步适配器被定义在类com.example.android.samplesync.syncadapter.SyncAdapter中。

 

A subclass of Application.

 

一个Application的子类。

 

This class acts as a factory for the sync adapter singleton. Use the onCreate() method to instantiate the sync adapter, and provide a static "getter" method to return the singleton to the onBind() method of the sync adapter's service.

 

这个类的行为如同一个同步适配器单实例的工厂。使用onCreate()方法来实例化同步适配器,并提供一个静态getter方法来返回同步适配器服务的onBind()方法的单实例。

 

Optional: A Service component that responds to requests from the system for user authentication.

 

可选的:一个Service组件,它响应来自系统的请求用于用户认证。

 

AccountManager starts this service to begin the authentication process. The service's onCreate() method instantiates an authenticator object. When the system wants to authenticate a user account for the application's sync adapter, it calls the service's onBind() method to get an IBinder for the authenticator. This allows the system to do cross-process calls to the authenticator's methods..

 

AccountManager启动这个服务以开始认证处理。服务的onCreate()方法实例化一个认证器对象。当系统想为应用程序的同步适配器认证一个用户账户,它调用服务的onBind()方法以为认证器获得一个IBinder。这允许系统执行对认证器方法的跨进程调用。(注:此处多了一个句号)

 

In the Sample Sync Adapter sample app, the class name of this service is com.example.android.samplesync.authenticator.AuthenticationService.

 

在示例同步适配器的示例应用中,这个服务的类名是com.example.android.samplesync.authenticator.AuthenticationService。

 

Optional: A concrete subclass of AbstractAccountAuthenticator that handles requests for authentication.

 

可选的:AbstractAccountAuthenticator的一个具体子类,它处理认证的请求。

 

This class provides methods that the AccountManager invokes to authenticate the user's credentials with the server. The details of the authentication process vary widely, based on the server technology in use. You should refer to the documentation for your server software to learn more about authentication.

 

这个类提供AccountManager用服务器调用用户证书的方法。认证的细节非常广泛地处理(注:处理方式非常多),基于正在使用的服务器技术。你应该参考你的服务器软件的文档以学习更多关于认证的内容。

 

In the Sample Sync Adapter sample app, the authenticator is defined in the class com.example.android.samplesync.authenticator.Authenticator.

 

在示例同步适配器的示例应用中,认证器被定义在类com.example.android.samplesync.authenticator.Authenticator。

 

XML files that define the sync adapter and authenticator to the system.

 

定义同步适配器和认证器给系统的XML文件。

 

The sync adapter and authenticator service components described previously are defined in elements in the application manifest. These elements contain child elements that provide specific data to the system:

 

之前描述的同步适配器和认证器服务组件被定义在应用程序清单中的元素里。这些元素包含子元素,它们提供特定数据给系统:

 

* The element for the sync adapter service points to the XML file res/xml/syncadapter.xml. In turn, this file specifies a URI for the web service that will be synchronized with the Contacts Provider, and an account type for the web service.

 

* 同步适配器服务的元素指向XML文件res/xml/syncadapter.xml。反过来,这个文件指定将用电话簿提供者同步的web服务的一个URI,以及web服务的一个账户类型。

 

* Optional: The element for the authenticator points to the XML file res/xml/authenticator.xml. In turn, this file specifies the account type that this authenticator supports, as well as UI resources that appear during the authentication process. The account type specified in this element must be the same as the account type specified for the sync adapter.

 

* 可选的:认证器的元素指向XML文件res/xml/authenticator.xml。反过来,这个文件指定这个认证器支持的账户类型,以及在认证处理期间出现的用户界面资源。这个元素指定的账户类型必须和同步适配器指定的账户类型相同。

 

-------------------------------

 

Social Stream Data

 

社交流数据

 

The ContactsContract.StreamItems and ContactsContract.StreamItemPhotos tables manage incoming data from social networks. You can write a sync adapter that adds stream data from your own network to these tables, or you can read stream data from these tables and display it in your own application, or both. With these features, your social networking services and applications can be integrated into Android's social networking experience.

 

ContactsContract.StreamItems和ContactsContract.StreamItemPhotos表管理来自社交网络的传入数据。你可以编写一个同步适配器,它添加来自你自己的网络的流数据到这些表,或者你可以从这些表中读取流数据并显示它在你自己的应用程序中,或者都有。使用这些特性,你的社交网络服务和应用程序可以被集成进Android的社交网络体验中。

 

Social stream text

 

社交流文本

 

Stream items are always associated with a raw contact. The RAW_CONTACT_ID links to the _ID value for the raw contact. The account type and account name of the raw contact are also stored in the stream item row.

 

流条目总是关联一个原始电话簿。RAW_CONTACT_ID链接到原始电话簿的_ID值。原始电话簿的账户类型和账户名称还被存储在流条目行中。

 

Store the data from your stream in the following columns:

 

在以下列中存储来自你的流的数据:

 

ACCOUNT_TYPE

 

Required. The user's account type for the raw contact associated with this stream item. Remember to set this value when you insert a stream item.

 

必需的。与这个流条目关联的原始电话簿的用户账户类型。记住设置这个值,当你插入一个流条目时。

 

ACCOUNT_NAME

 

Required. The user's account name for the raw contact associated with this stream item. Remember to set this value when you insert a stream item.

 

必需的。与这个流条目关联的原始电话簿的用户账户名。记住设置这个值,当你插入一个流条目时。

 

Identifier columns

 

标识符列

 

Required. You must insert the following identifier columns when you insert a stream item:

 

必需的。你必须插入以下标识符列,当你插入一个流条目时:

 

* CONTACT_ID: The _ID value of the contact that this stream item is associated with.

 

* CONTACT_ID:这个流条目被关联到的电话簿的_ID值。

 

* CONTACT_LOOKUP_KEY: The LOOKUP_KEY value of the contact this stream item is associated with.

 

* CONTACT_LOOKUP_KEY:这个流条目被关联到的电话簿的LOOKUP_KEY值。

 

* RAW_CONTACT_ID: The _ID value of the raw contact that this stream item is associated with.

 

* RAW_CONTACT_ID:这个流条目被关联到的原始电话簿的_ID值。

 

COMMENTS

 

Optional. Stores summary information that you can display at the beginning of a stream item.

 

可选。存储你可以显示在一个流条目开头的摘要信息。

 

TEXT

 

The text of the stream item, either the content that was posted by the source of the item, or a description of some action that generated the stream item. This column can contain any formatting and embedded resource images that can be rendered by fromHtml(). The provider may truncate or ellipsize long content, but it will try to avoid breaking tags.

 

流条目的文本,要么是被条目的源发送的内容,要么是生成流条目的一些动作的一个描述。这个列可以包含可被fromHtml()渲染的任意格式化和内嵌的资源图片。提供者可以截断或省略(注:ellipsize应该是ellipsis的变形,在Android中表示用省略号替换过长的文本)长内容,但它将尝试避免破坏标签。

 

TIMESTAMP

 

A text string containing the time the stream item was inserted or updated, in the form of milliseconds since epoch. Applications that insert or update stream items are responsible for maintaining this column; it is not automatically maintained by the Contacts Provider.

 

一个文本字符串,包含流条目被插入或更新的时间,以从纪元算起的毫秒的形式。插入或更新流条目的应用程序负责维护这个列;它不自动地被电话簿提供者维护。

 

To display identifying information for your stream items, use the RES_ICON, RES_LABEL, and RES_PACKAGE to link to resources in your application.

 

为了显示你的流条目的标识信息,请使用RES_ICON,RES_LABEL,和RES_PACKAGE来链接到你的应用程序的资源。

 

The ContactsContract.StreamItems table also contains the columns SYNC1 through SYNC4 for the exclusive use of sync adapters.

 

ContactsContract.StreamItems表还包含列SYNC1至SYNC4供同步适配器的专门使用。

 

Social stream photos

 

社交流照片

 

The ContactsContract.StreamItemPhotos table stores photos associated with a stream item. The table's STREAM_ITEM_ID column links to values in the _ID column of ContactsContract.StreamItems table. Photo references are stored in the table in these columns:

 

ContactsContract.StreamItemPhotos表存储与一个流条目关联的照片。表的STREAM_ITEM_ID列链接到ContactsContract.StreamItems表的_ID列中的值。照片引用被存储在表中这些列里:

 

PHOTO column (a BLOB).

 

PHOTO列(一个BLOB)。

 

A binary representation of the photo, resized by the provider for storage and display. This column is available for backwards compatibility with previous versions of the Contacts Provider that used it for storing photos. However, in the current version you should not use this column to store photos. Instead, use either PHOTO_FILE_ID or PHOTO_URI (both of which are described in the following points) to store photos in a file. This column now contains a thumbnail of the photo, which is available for reading.

 

照片的一个二进制表示,被提供者为了存储和显示而改变大小。这个列的向后兼容性是可用的,对于使用它来存储照片的之前电话簿提供者的版本来说。然而,在当前版本中你不应使用这个列来存储照片。相反,使用PHOTO_FILE_ID或PHOTO_URI(两者均在以下要点中被描述)以存储照片在一个文件中。这个列现在包含该照片的一个缩略图,它对于读取是可用的。

 

PHOTO_FILE_ID

 

A numeric identifier of a photo for a raw contact. Append this value to the constant DisplayPhoto.CONTENT_URI to get a content URI pointing to a single photo file, and then call openAssetFileDescriptor() to get a handle to the photo file.

 

一个原始电话簿的照片的一个数字标识符。尾加这个值到常量DisplayPhoto.CONTENT_URI以获得一个指向一个单一电话簿文件的一个内容URI,然后调用openAssetFileDescriptor()以打开一个指向该照片文件的句柄。

 

PHOTO_URI

 

A content URI pointing directly to the photo file for the photo represented by this row. Call openAssetFileDescriptor() with this URI to get a handle to the photo file.

 

一个内容URI直接地指向这个行代表的照片的照片文件。用这个URI调用openAssetFileDescriptor()以获得一个指向照片文件的句柄。

 

Using the social stream tables

 

使用社交流表

 

These tables work the same as the other main tables in the Contacts Provider, except that:

 

这些表和电话簿提供者中的其它主要表相同地工作,除了:

 

* These tables require additional access permissions. To read from them, your application must have the permission READ_SOCIAL_STREAM. To modify them, your application must have the permission WRITE_SOCIAL_STREAM.

 

* 这些表需要额外的访问权限。为了读取它们,你的应用程序必须拥有权限READ_SOCIAL_STREAM。为了修改它们,你的应用程序必须拥有权限WRITE_SOCIAL_STREAM。

 

* For the ContactsContract.StreamItems table, the number of rows stored for each raw contact is limited. Once this limit is reached, the Contacts Provider makes space for new stream item rows by automatically deleting the rows having the oldest TIMESTAMP. To get the limit, issue a query to the content URI CONTENT_LIMIT_URI. You can leave all the arguments other than the content URI set to null. The query returns a Cursor containing a single row, with the single column MAX_ITEMS.

 

* 对于ContactsContract.StreamItems表,为每个原始电话簿而被存储的行数受到限制的。一旦到达这个限制,电话簿提供者制造空间给新的流条目,通过自动地检测拥有最旧TIMESTAMP的行。为了获得这个限制,发送一个查询给内容URI CONTENT_LIMIT_URI。你可以让不同于内容URI的所有参数设置为null。查询返回一个Cursor,它包含一个单一行,带有单一列MAX_ITEMS。

 

The class ContactsContract.StreamItems.StreamItemPhotos defines a sub-table of ContactsContract.StreamItemPhotos containing the photo rows for a single stream item.

 

类ContactsContract.StreamItems.StreamItemPhotos定义ContactsContract.StreamItemPhotos的一个子表,它包含一个单一流条目的照片行。

 

Social stream interactions

 

社交流交互

 

The social stream data managed by the Contacts Provider, in conjunction with the device's contacts application, offers a powerful way to connect your social networking system with existing contacts. The following features are available:

 

被电话簿提供者管理的社交流数据,与设备的电话簿应用程序一起,提供一个强大方式以连接你的社交网络系统与现存电话簿。以下特性是可用的:

 

* By syncing your social networking service to the Contacts Provider with a sync adapter, you can retrieve recent activity for a user's contacts and store it in the ContactsContract.StreamItems and ContactsContract.StreamItemPhotos tables for later use.

 

* 通过用一个同步适配器同步你的社交网络服务到电话簿提供者,你可以取出一个用户的电话簿的最近活动并存储它在ContactsContract.StreamItems和ContactsContract.StreamItemPhotos表中供以后使用。

 

* Besides regular synchronization, you can trigger your sync adapter to retrieve additional data when the user selects a contact to view. This allows your sync adapter to retrieve high-resolution photos and the most recent stream items for the contact.

 

* 除了常规的同步,你还可以触发你的同步适配器来接收额外数据,当用户选择一个电话簿来查看。这允许你的同步适配器接收高清照片和该电话簿的最近流条目。

 

* By registering a notification with the device's contacts application and the Contacts Provider, you can receive an intent when a contact is viewed, and at that point update the contact's status from your service. This approach may be faster and use less bandwidth than doing a full sync with a sync adapter.

 

* 通过用设备的电话簿应用程序和电话簿提供者来注册一个通知,当一个电话簿被查看时你可以接收一个意图,并且在那个时间点上更新来自你的服务的电话簿状态。这种方法可能更快且使用比用一个同步适配器执行一次完全同步更少的带宽。

 

* Users can add a contact to your social networking service while looking at the contact in the device's contacts application. You enable this with the "invite contact" feature, which you enable with a combination of an activity that adds an existing contact to your network, and an XML file that provides the device's contacts application and the Contacts Provider with the details of your application.

 

* 用户可以添加一个电话簿到你的社交网络服务,当查看设备电话簿应用程序中的电话簿时。你用“邀请电话簿”特性来使能它,你使能它,通过组合添加一个现存电话簿到你的网络的一个活动,以及用你的应用程序的明细来提供设备电话簿应用程序和电话簿提供者的一个XML文件。

 

Regular synchronization of stream items with the Contacts Provider is the same as other synchronizations. To learn more about synchronization, see the section Contacts Provider Sync Adapters. Registering notifications and inviting contacts are covered in the next two sections.

 

使用电话簿提供者的常规流条目同步化与其它同步化相同。为了学习更多关于同步化的内容,请参见章节电话簿提供者同步适配器。注册通知和邀请电话簿在下两个章节中被涵盖。

 

Registering to handle social networking views

 

注册以处理社交网络视图

 

To register your sync adapter to receive notifications when the user views a contact that's managed by your sync adapter:

 

为了注册你的同步适配器以在用户查看一个被你的同步适配器管理的电话簿时接收通知:

 

1. Create a file named contacts.xml in your project's res/xml/ directory. If you already have this file, you can skip this step.

 

1. 创建一个名为contacts.xml的文件在你的工程的res/xml/目录中。如果你已经拥有这个文件,你可以跳过这一步。

 

2. In this file, add the element . If this element already exists, you can skip this step.

 

2. 在这个文件中,添加元素。如果这个元素已经存在,你可以跳过这一步。

 

3. To register a service that is notified when the user opens a contact's detail page in the device's contacts application, add the attribute viewContactNotifyService="serviceclass" to the element, where serviceclass is the fully-qualified classname of the service that should receive the intent from the device's contacts application. For the notifier service, use a class that extends IntentService, to allow the service to receive intents. The data in the incoming intent contains the content URI of the raw contact the user clicked. From the notifier service, you can bind to and then call your sync adapter to update the data for the raw contact.

 

3. 为了注册一个服务,它被通知当用户在设备的电话簿应用程序中打开一个电话簿的明细页时,请添加属性viewContactNotifyService="serviceclass"到该元素,其中serviceclass是服务的完全修饰类名,它应该接收来自设备的电话簿应用程序的意图。对于通知方服务,请使用一个继承自IntentService的类,以允许服务接收意图。输入意图中的数据包含用户点击的原始电话簿的内容URI。来自通知方服务,你可以绑定然后调用你的同步适配器以更新原始电话簿的数据。

 

To register an activity to be called when the user clicks on a stream item or photo or both:

 

为了注册一个活动以被调用当用户客户点击在一个流条目上或照片或两者上:

 

1. Create a file named contacts.xml in your project's res/xml/ directory. If you already have this file, you can skip this step.

 

1. 创建一个名为contacts.xml的文件在你的工程的res/xml/目录中。如果你已经拥有这个文件,你可以跳过这一步。

 

2. In this file, add the element . If this element already exists, you can skip this step.

 

2. 在这个文件中,添加元素。如果这个元素已经存在,你可以跳过这一步。

 

3. To register one of your activities to handle the user clicking on a stream item in the device's contacts application, add the attribute viewStreamItemActivity="activityclass" to the element, where activityclass is the fully-qualified classname of the activity that should receive the intent from the device's contacts application.

 

3. 为了注册你的其中一个活动以处理在设备的电话簿应用程序中用户在一个流条目上的点击,请添加属性viewStreamItemActivity="activityclass"到该元素,这里activityclass是应该从设备的电话簿应用程序中接收意图的活动的完全修饰类名。

 

4. To register one of your activities to handle the user clicking on a stream photo in the device's contacts application, add the attribute viewStreamItemPhotoActivity="activityclass" to the element, where activityclass is the fully-qualified classname of the activity that should receive the intent from the device's contacts application.

 

4. 为了注册你的其中一个活动以处理用户在设备的电话簿应用程序中在一个流照片上的点击,请添加属性viewStreamItemPhotoActivity="activityclass"到该元素,这里activityclass是应该从设备的电话簿应用程序中接收意图的活动的完全修饰类名。

 

The element is described in more detail in the section element.

 

元素在章节元素中更详细地描述。

 

The incoming intent contains the content URI of the item or photo that the user clicked. To have separate activities for text items and for photos, use both attributes in the same file.

 

输入意图包含该条目的内容URI或者用户点击的照片。为了拥有分离的用于文本条目和用于照片的活动,请在同一个文件中都使用这两个属性。

 

Interacting with your social networking service

 

与你的社交网络服务交互

 

Users don't have to leave the device's contacts application to invite a contact to your social networking site. Instead, you can have the device's contacts app send an intent for inviting the contact to one of your activities. To set this up:

 

用户不必离开设备的电话簿应用程序以邀请一个电话簿到你的社交网络网站。相反,你可以让设备的电话簿应用发送一个用于邀请电话簿的意图到你的其中一个活动。为了配置它:

 

1. Create a file named contacts.xml in your project's res/xml/ directory. If you already have this file, you can skip this step.

 

1. 创建一个名为contacts.xml的文件在你的工程的res/xml/目录中。如果你已经拥有这个文件,你可以跳过这个步骤。

 

2. In this file, add the element . If this element already exists, you can skip this step.

 

2. 在这个文件中,添加元素。如果这个元素已经存在,你可以跳过这一步。

 

3. Add the following attributes:

 

3. 添加以下属性:

 

* inviteContactActivity="activityclass"

 

* inviteContactActionLabel="@string/invite_action_label"

 

The activityclass value is the fully-qualified classname of the activity that should receive the intent. The invite_action_label value is a text string that's displayed in the Add Connection menu in the device's contacts application.

 

activityclass的值是应该接收该意图的活动的完全修饰类名。invite_action_label的值是一个文本字符串,它被显示在设备的电话簿提供者里添加连接菜单中。

 

-------------------------------

 

Note: ContactsSource is a deprecated tag name for ContactsAccountType.

 

注意:ContactsSource是ContactsAccountType的一个已废弃标签名。

 

-------------------------------

 

contacts.xml reference

 

contacts.xml参考

 

The file contacts.xml contains XML elements that control the interaction of your sync adapter and application with the contacts application and the Contacts Provider. These elements are described in the following sections.

 

文件contacts.xml包含XML元素,它们控制你的同步适配器和应用程序与电话簿应用程序和电话簿提供者之间的交互(注:待考)。这些元素被描述在以下章节中。

 

element

 

元素

 

The element controls the interaction of your application with the contacts application. It has the following syntax:

 

元素控制你的应用程序与电话簿应用程序之间的交互。它拥有以下语法:

 

-------------------------------

 

        xmlns:android="http://schemas.android.com/apk/res/android"

        inviteContactActivity="activity_name"

        inviteContactActionLabel="invite_command_text"

        viewContactNotifyService="view_notify_service"

        viewGroupActivity="group_view_activity"

        viewGroupActionLabel="group_action_text"

        viewStreamItemActivity="viewstream_activity_name"

        viewStreamItemPhotoActivity="viewphotostream_activity_name">

 

-------------------------------

 

contained in:

 

被包含在:

 

res/xml/contacts.xml

 

can contain:

 

可以包含:

 

 

Description:

 

描述:

 

Declares Android components and UI labels that allow users to invite one of their contacts to a social network, notify users when one of their social networking streams is updated, and so forth.

 

声明Android组件和用户界面标签,它们允许用户邀请他们电话簿中的其中一个到一个社交网络,当他们的社交网络流的其中一个被更新,等等时,提醒用户。

 

Notice that the attribute prefix android: is not necessary for the attributes of .

 

注意属性前缀android:不是必需的,对于的属性来说。

 

Attributes:

 

属性:

 

inviteContactActivity

 

The fully-qualified class name of the activity in your application that you want to activate when the user selects Add connection from the device's contacts application.

 

在你的应用程序中的活动完全修饰类名,你希望激活它当用户从设备的电话簿应用程序中选择添加连接时。

 

inviteContactActionLabel

 

A text string that is displayed for the activity specified in inviteContactActivity, in the Add connection menu. For example, you can use the string "Follow in my network". You can use a string resource identifier for this label.

 

一个文本字符串,它为在inviteContactActivity中指定的活动而被显示,在添加链接菜单中。例如,你可以使用字符串“在我的网络中跟随”。你可以为这个标签使用一个字符串资源标识符。

 

viewContactNotifyService

 

The fully-qualified class name of a service in your application that should receive notifications when the user views a contact. This notification is sent by the device's contacts application; it allows your application to postpone data-intensive operations until they're needed. For example, your application can respond to this notification by reading in and displaying the contact's high-resolution photo and most recent social stream items. This feature is described in more detail in the section Social stream interactions. You can see an example of the notification service in the NotifierService.java file in the SampleSyncAdapter sample app.

 

你的应用程序中的一个服务的完全修饰类名,它应该在用户查看一个电话簿时接收通知。这个通知被设备的电话簿应用程序发送;它允许你的应用程序推迟数据密集操作直至它们被需要。例如,你的应用程序可以通过读入和显示电话簿的高清照片和最近社交流条目来响应这个通知。这个特性被更详细地描述在章节社交流交互。你可以在SampleSyncAdapter示例应用中的NotifierService.java文件里看到通知服务的一个示例。

 

viewGroupActivity

 

The fully-qualified class name of an activity in your application that can display group information. When the user clicks the group label in the device's contacts application, the UI for this activity is displayed.

 

在你的应用程序中的可以显示组信息的一个活动的完全修饰类名。当用户点击设备的电话簿应用程序中的组标签时,这个活动的用户界面被显示。

 

viewGroupActionLabel

 

The label that the contacts application displays for a UI control that allows the user to look at groups in your application.

 

电话簿应用程序为一个用户界面控件而显示的标签,允许用户在你的应用程序中看到组。

 

For example, if you install the Google+ application on your device and you sync Google+ with the contacts application, you'll see Google+ circles listed as groups in your contacts application's Groups tab. If you click on a Google+ circle, you'll see people in that circle listed as a "group". At the top of the display, you'll see a Google+ icon; if you click it, control switches to the Google+ app. The contacts application does this with the viewGroupActivity, using the Google+ icon as the value of viewGroupActionLabel.

 

例如,如果你在你的设备上安装Google+应用程序而你使用电话簿应用程序同步Google+,那么你将在你的电话簿应用程序的组标签中看到Google+圆圈(注:圈子?)被列举作为组。如果你点击一个Google+圈,你将看到在这那个圈中的人被列举作为一个“组”。在显示屏的顶部,你将看到一个Google+图标;如果你点击它,控制流会切换至Google+应用。电话簿应用程序用viewGroupActivity做这件事,通过使用Google+图标作为viewGroupActionLabel的值。

 

A string resource identifier is allowed for this attribute.

 

一个字符串资源标识符被允许用于这个属性。

 

viewStreamItemActivity

 

The fully-qualified class name of an activity in your application that the device's contacts application launches when the user clicks a stream item for a raw contact.

 

在你的应用程序中的一个活动的完全修饰类名,当用户点击一个原始电话簿的一个流条目时设备的电话簿应用程序启动它。

 

viewStreamItemPhotoActivity

 

The fully-qualified class name of an activity in your application that the device's contacts application launches when the user clicks a photo in the stream item for a raw contact.

 

在你的应用程序中的一个活动的完全修饰类名,当用户点击一个原始电话簿的流条目中的一个照片时设备的电话簿应用程序启动它。

 

element

 

元素

 

The element controls the display of your application's custom data rows in the contacts application's UI. It has the following syntax:

 

元素控制在电话簿应用程序中你的应用程序的定制数据行的显示。它拥有以下语法:

 

-------------------------------

 

        android:mimeType="MIMEtype"

        android:icon="icon_resources"

        android:summaryColumn="column_name"

        android:detailColumn="column_name">

 

-------------------------------

 

contained in:

 

被包含在:

 

 

Description:

 

描述:

 

Use this element to have the contacts application display the contents of a custom data row as part of the details of a raw contact. Each child element of represents a type of custom data row that your sync adapter adds to the ContactsContract.Data table. Add one element for each custom MIME type you use. You don't have to add the element if you have a custom data row for which you don't want to display data.

 

使用这个元素让电话簿应用程序显示一个自定义数据行的内容作为一个原始电话簿的明细的一部分。的每个子元素代表一个类型的自定义数据行,你的同步适配器添加它到ContactsContract.Data表。为你使用的每个自定义MIME类型添加一个元素。你不必添加该元素,如果你拥有一个自定义数据行,你不希望为它显示数据。

 

Attributes:

 

属性:

 

android:mimeType

 

The custom MIME type you've defined for one of your custom data row types in the ContactsContract.Data table. For example, the value vnd.android.cursor.item/vnd.example.locationstatus could be a custom MIME type for a data row that records a contact's last known location.

 

你已经为ContactsContract.Data表中你的定制数据行类型定义的定制MIME类型。例如,值vnd.android.cursor.item/vnd.example.locationstatus可以是一个记录电话簿最近已知位置的数据行的一个定制MIME类型。

 

android:icon

 

An Android drawable resource that the contacts application displays next to your data. Use this to indicate to the user that the data comes from your service.

 

一个Android可绘画对象资源,电话簿应用程序在你的数据旁边显示它。使用它来指示用户数据来自你的服务。

 

android:summaryColumn

 

The column name for the first of two values retrieved from the data row. The value is displayed as the first line of the entry for this data row. The first line is intended to be used as a summary of the data, but that is optional. See also android:detailColumn.

 

从数据行中取出的两个值中的第一个的列名。该值被显示作为这个数据行的记录的第一行。第一行倾向于用作数据的一个摘要,但那时可选的。另见android:detailColumn。

 

android:detailColumn

 

The column name for the second of two values retrieved from the data row. The value is displayed as the second line of the entry for this data row. See also android:summaryColumn.

 

从数据行中取出的两个值的第二个的列名。该值被显示作为这个数据行的记录的第二行。另见android:summaryColumn。

 

-------------------------------

 

Additional Contacts Provider Features

 

额外的电话簿提供者特性

 

Besides the main features described in previous sections, the Contacts Provider offers these useful features for working with contacts data:

 

除了在前面章节中描述的主要特性外,电话簿提供者为处理电话簿数据提供这些有用的特性:

 

* Contact groups

 

* 电话簿组

 

* Photo features

 

* 照片特性

 

Contact groups

 

电话簿组

 

The Contacts Provider can optionally label collections of related contacts with group data. If the server associated with a user account wants to maintain groups, the sync adapter for the account's account type should transfer groups data between the Contacts Provider and the server. When users add a new contact to the server and then put this contact in a new group, the sync adapter must add the new group to the ContactsContract.Groups table. The group or groups a raw contact belongs to are stored in the ContactsContract.Data table, using the ContactsContract.CommonDataKinds.GroupMembership MIME type.

 

电话簿提供者可以可选地用组数据来标签化相关的电话簿集合。如果与一个用户账户有关的服务器希望维护组,那么该账户的账户类型的同步适配器应该在电话簿提供者和服务器之间传输数据。当用户添加一个新的电话簿到服务器,然后放置这个电话簿在一个新的组里时。同步适配器必须添加新组到ContactsContract.Groups表。一个原始电话簿所述的一个或多个组被存储在ContactsContract.Data表中,使用ContactsContract.CommonDataKinds.GroupMembership的MIME类型。

 

If you're designing a sync adapter that will add raw contact data from server to the Contacts Provider, and you aren't using groups, then you need to tell the Provider to make your data visible. In the code that is executed when a user adds an account to the device, update the ContactsContract.Settings row that the Contacts Provider adds for the account. In this row, set the value of the Settings.UNGROUPED_VISIBLE column to 1. When you do this, the Contacts Provider will always make your contacts data visible, even if you don't use groups.

 

如果你正在设计一个同步适配器,它将添加来自服务器的原始电话簿数据到电话簿提供者,而你不是正在使用组,那么你需要告诉提供者以使你的数据可见。在当一个用户添加一个账户到设备时被执行的代码中,更新电话簿提供者为该账户而添加的 ContactsContract.Settings行。在这行中,设置Settings.UNGROUPED_VISIBLE列的值为1。当你这样做时,电话簿提供者将总是使你的电话簿数据可见,即便你不使用组。

 

Contact photos

 

电话簿照片

 

The ContactsContract.Data table stores photos as rows with MIME type Photo.CONTENT_ITEM_TYPE. The row's CONTACT_ID column is linked to the _ID column of the raw contact to which it belongs. The class ContactsContract.Contacts.Photo defines a sub-table of ContactsContract.Contacts containing photo information for a contact's primary photo, which is the primary photo of the contact's primary raw contact. Similarly, the class ContactsContract.RawContacts.DisplayPhoto defines a sub-table of ContactsContract.RawContacts containing photo information for a raw contact's primary photo.

 

ContactsContract.Data表使用MIME类型Photo.CONTENT_ITEM_TYPE存储照片作为行。行的CONTACT_ID列被链接至它所属的原始电话簿的_ID列。类ContactsContract.Contacts.Photo定义包含一个电话簿主要照片的照片信息的ContactsContract.Contacts的一个子表,它是该电话簿的主要原始电话簿的主要照片。类似地,类ContactsContract.RawContacts.DisplayPhoto定义包含一个原始电话簿主要照片的照片信息的ContactsContract.RawContacts的一个子表。

 

The reference documentation for ContactsContract.Contacts.Photo and ContactsContract.RawContacts.DisplayPhoto contain examples of retrieving photo information. There is no convenience class for retrieving the primary thumbnail for a raw contact, but you can send a query to the ContactsContract.Data table, selecting on the raw contact's _ID, the Photo.CONTENT_ITEM_TYPE, and the IS_PRIMARY column to find the raw contact's primary photo row.

 

ContactsContract.Contacts.Photo和ContactsContract.RawContacts.DisplayPhoto的参考文档包含取出照片信息的示例。没有便利方法用于取出一个原始电话簿的主缩略图,但你可以发送一条查询到ContactsContract.Data表,在原始电话簿的_ID,Photo.CONTENT_ITEM_TYPE和IS_PRIMARY列上选择,以找到原始电话簿的主照片行。

 

Social stream data for a person may also include photos. These are stored in the ContactsContract.StreamItemPhotos table, which is described in more detail in the section Social stream photos.

 

一个人的社交流数据还可能包含照片。这些被存储在ContactsContract.StreamItemPhotos表中,它在章节社交流照片中被更详细地描述。

 

-------------------------------

 

Except as noted, this content is licensed under Apache 2.0. For details and restrictions, see the Content License.

 

除特别说明外,本文在Apache 2.0下许可。细节和限制请参考内容许可证。

 

Android 4.1 r1 - 30 Jun 2012 0:55

 

-------------------------------

 

Portions of this page are modifications based on work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.

 

此页部分内容,是基于Android开源项目所创建和共享的工作,并且根据知识共享2.5署名许可证描述的条款来使用的修改版。

你可能感兴趣的:(contacts,android,contacts)