如何检索从提供的数据。
联系人提供者是一个Android内容提供商组成部分。它保持关于一个人三种类型的数据,其每一个对应于由提供者提供,如在图1中所示的表:
图1.联系人提供商表结构。
这三个表是由他们的合同类的名称通常称为。类定义的URI的内容,列名,并通过使用表列值的常数:
ContactsContract.Contacts表
行代表不同的人,根据原料接触的行聚集。
ContactsContract.RawContacts表
含有一个人的数据的特定用户帐户和类型的摘要,行。
ContactsContract.Data表
含有原料接触的细节,诸如电子邮件地址或电话号码的行。
合同类ContactsContract代表的其他表是联系人提供用于管理其操作或支持该设备的联系人或电话应用程序的特定功能辅助表。
生接触
一个原始的接触代表单个帐户类型和帐户名称来一个人的数据。由于联系人提供商允许一个以上的在线服务数据的一个人的来源,联系人提供商允许为同一人多次接触原料。多生交往还允许用户将个人数据从多个帐户从同一账户类型相结合。
最为原始接触的数据都没有存储在ContactsContract.RawContacts表。相反,它存储在ContactsContract.Data表的一个或多个行。每个数据行都有一个包含其母公司ContactsContract.RawContacts行的RawContacts._ID值的列Data.RAW_CONTACT_ID。
重要原料接触列
在ContactsContract.RawContacts表中的重要列列于表1。请仔细阅读表后,下面的注意事项:
表1.重要原料接触列。
列名使用注意事项
ACCOUNT_NAME的帐户类型这是此生接触的来源帐户名。例如,谷歌帐户的帐户名是设备所有者的Gmail地址之一。请参阅帐户类型的详细信息下一个条目。这个名字的格式是具体到其帐户类型。它不一定是电子邮件地址。
ACCOUNT_TYPE帐户类型这是此生接触的来源。例如,谷歌帐户的帐户类型是com.google。永远与你自己的域或控制域标识符合您的帐户类型。这将确保您的帐户类型是独一无二的。通常提供的联系人数据的帐户类型具有与联系人同步提供相关的同步适配器。
删除了“已删除”标志的原始接触。此标志允许联系人提供商保持内部行,直到同步适配器能够从他们的服务器中删除的行,然后最终删除存储库中的行。
笔记
以下是有关ContactsContract.RawContacts表重要提示:
一个原始联系人的姓名没有存储在其ContactsContract.RawContacts一行。相反,它存储在ContactsContract.Data表,在一个ContactsContract.CommonDataKinds.StructuredName行。一个原始联系人只有一行这种类型的ContactsContract.Data表。
注意:要在原始接触一行使用自己的帐户数据,必须先用的AccountManager注册。要做到这一点,提示用户帐户类型和他们的帐户名称添加到帐户列表。如果你不这样做,联系人提供商将自动删除您的原始联系行。
例如,如果你希望你的应用程序保持接触数据与域com.example.dataservice基于Web的服务,用户的帐号为您服务是[email protected],用户必须先添加您的应用程序之前的账户“类型”(com.example.dataservice)和账户“名”([email protected])可以加生接触的行。您可以在文档中解释这一要求给用户,或者你可以提示用户添加的种类和名称,或两者兼而有之。帐户类型和帐户名称以更详细的下一节描述。
原始接触数据来源
要了解如何接触生的工作,考虑到用户的“艾米莉·狄金森”谁拥有她的设备上定义以下三个用户帐户:
[email protected]
[email protected]
Twitter帐户“belle_of_amherst”
该用户已启用的帐户设置,所有这三个帐户同步联系人。
假设艾米莉狄金森打开浏览器窗口,登录到Gmail作为[email protected],打开联系人,并增加了“托马斯·希金森”。后来,她登录到Gmail作为[email protected]并发送电子邮件至“托马斯希金森”,它会自动添加他为联系人。她还遵循“colonel_tom”在Twitter(托马斯·希金森的Twitter ID)。
联系人提供商创建三个原始联系人作为这项工作的结果:
对于“托马斯·希金森”A原接触[email protected]有关。用户帐户类型是谷歌。
对于“托马斯·希金森”第二生接触[email protected]有关。用户帐户类型也是谷歌。有即使名称是相同的一个以前的名称,因为对于不同的用户帐户中加入人的第二生接触。
对于“托马斯·希金森”与“belle_of_amherst”有关的第三个原料接触。用户帐户类型是Twitter的。
数据
如前面所指出的,对于一个原始联系人的数据被存储在链接到原始接触的_ID值ContactsContract.Data行。这允许单个原料接触到具有相同的数据类型的多个实例,例如电子邮件地址或电话号码。例如,如果“托马斯·希金森”对于[email protected](与谷歌帐户[email protected]相关托马斯·希金森原料接触行)具有[email protected]的家庭电子邮件地址和的工作电子邮件地址[email protected],联系人提供商存储两个电子邮件地址,行并将它们都链接到原始的接触。
注意,不同类型的数据被存储在该单个表。显示姓名,电话号码,电子邮件,邮寄地址,照片和网站的细节行中的ContactsContract.Data表中的所有发现。为了帮助实现这一点,ContactsContract.Data表中有描述性的名字,并与通用名称等一些列。一个描述名称列的内容具有相同的含义而不管该行中的数据的类型,而通用名栏的内容具有取决于数据的类型不同的含义。
描述列名
描述的列名的一些实例是:
RAW_CONTACT_ID
此数据的原始接触的_ID列的值。
MIMETYPE
类型存储在该行中的数据,表示为自定义的MIME类型。在联系人提供程序使用ContactsContract.CommonDataKinds的子类中定义的MIME类型。这些MIME类型是开源的,并且可以通过与联系人提供商合作的任何应用程序或同步适配器一起使用。
IS_PRIMARY
如果这种类型的数据行的,就可能出现一次以上的原料接触时,IS_PRIMARY列标志包含该类型的主数据中的数据行。例如,如果用户长时间按下一个电话号码供一个接触,并选择设置默认,则含有该号码的ContactsContract.Data行都有IS_PRIMARY列设置为非零值。
通用列名
有迹象表明,一般可通过DATA15名为DATA1 15通用列和只应由同步适配器一起使用的另外四个通用列SYNC1通过SYNC4。通用列名常量总是工作,无论行包含数据的类型。
数据1列索引。联系人提供始终使用此列,该提供者期望将一个查询的最频繁的目标的数据。例如,电子邮件行,该列包含实际的电子邮件地址。
按照惯例,该列DATA15被保留用于存储二进制大对象(BLOB)数据如照片缩略图。
特定类型的列名
以促进与特定类型的行的列工作,联系人提供程序还提供了类型特异性的列名的常数,在ContactsContract.CommonDataKinds的子类所定义。常量只是给予不同的常量名以相同的列名,它可以帮助您在特定类型的一行访问数据。
例如,ContactsContract.CommonDataKinds.Email类定义特定类型的列名常量具有MIME类型Email.CONTENT_ITEM_TYPE一个ContactsContract.Data一行。该类包含电子邮件地址列中的常量地址。地址的实际值是“DATA1”,这是相同的列的总称。
注意:不要使用有供应商的预定义的MIME类型中的一种一排自己的自定义数据添加到ContactsContract.Data表。如果你这样做,可能会丢失数据或导致供应出现故障。例如,你不应该包含用户名,而不是在列DATA1的电子邮件地址的MIME类型Email.CONTENT_ITEM_TYPE添加行。如果您使用自己的自定义MIME类型的行,然后你可以自由定义自己的特定类型的列名,并按照自己的喜好使用的列。
图2显示了列和数据列如何描述出现在ContactsContract.Data行,怎么特定类型的列名“叠加”的通用列名
图2.特定于类型的列名和通用列名。
特定类型的列名班
表2列出了最常用的类型特定的列名的类:
表2.特定于类型的列名班
数据说明的映射类类型
ContactsContract.CommonDataKinds.StructuredName名称数据与此数据列相关的原料接触。一个原始联系人只有这些行之一。
ContactsContract.CommonDataKinds.Photo主要的照片与此数据行相关的原料接触。一个原始联系人只有这些行之一。
ContactsContract.CommonDataKinds.Email的电子邮件地址与此数据行相关的原料接触。的裸联系人可以有多个电子邮件地址。
ContactsContract.CommonDataKinds.StructuredPostal邮政地址与此数据行相关的原料接触。的裸联系人可以有多个邮政地址。
ContactsContract.CommonDataKinds.GroupMembership链接的原始接触以在联系人提供的组中的一个的标识符。组是一个帐户类型和帐户名的可选功能。他们在更详细的部分联系人组描述。
往来
联系人提供结合了所有帐户类型和帐户名称原料接触行形成接触。这便于显示和修改所有用户已收集的人的数据。联系人管理供应商创造新的联系人行,和生的联系人与现有联系人行聚集。无论是应用还是同步适配器被允许添加联系人,并在接触一些列的列是只读的。
注意:如果您尝试添加联系人到联系人提供与INSERT(),你会得到一个UnsupportedOperationException异常。如果您尝试更新的列为列“只读”的更新将被忽略。
联系人提供商创建响应增加了一个新的原始联系人不匹配任何现有的接触一个新的联系人。提供者也确实本如果以这样的方式现有原始联系人的数据的变化,它不再接触的匹配其所先前连接。如果一个应用程序或同步适配器创建一个新的原始接触,做匹配现有的接触,新的原始联系人汇集到现有的联系人。
联系人提供链接的联系人行其原料的接触与排在联系人表中的联系人行的_ID列。原料接触表ContactsContract.RawContacts的CONTACT_ID列包含与每个原始联系人行相关联的联系人行_ID值。
该ContactsContract.Contacts表还具有列LOOKUP_KEY这是一个“永久”链接到联系人行。由于联系人提供商自动保持联系,它可以响应聚合或同步更改联系人行的_ID价值。即使发生这种情况,内容URI CONTENT_LOOKUP_URI接触的LOOKUP_KEY组合仍然将指向接触行,所以你可以使用LOOKUP_KEY保有环节为“最爱”的接触,等等。此列有它自己的格式是无关的_ID列的格式。
图3显示了三个主要的表是如何相互关联。
图3.联系人,原始联系人和详细信息表之间的关系。
从数据同步适配器
用户输入联系人的数据直接进入设备,但数据还流入从Web服务通过同步适配器,它自动化设备和服务之间的数据传输联系人提供商。同步适配器在系统的控制下在后台运行,并且他们叫ContentResolver的方法来管理数据。
在Android中,一个同步适配器适用于由账户类型确定的Web服务。每个同步适配器一个帐户类型的作品,但它可以支持多个帐户名该类型。帐户类型和帐户名称中的原始数据接触的部分来源是简要说明。以下定义提供更多的细节,描述了帐户类型和名称如何与同步适配器和服务。
帐户类型
标识该用户已经存储的数据的服务。大部分时间,用户的服务进行认证。例如,谷歌联系人是一个帐户类型,由代码google.com标识。此值对应于由的AccountManager使用的帐户类型。
用户名
标识帐户类型的特定帐户或登录。谷歌联系人账户是一样的谷歌账户,其中有一个电子邮件地址作为帐户名。其他服务可能会使用单字名或数字ID。
帐户类型不必是唯一的。用户可以配置多个谷歌帐户的联系人及其数据下载到联系人供应商;如果用户有一组用于个人帐户名个人联系人,和另一组的工作,这可能发生。账户名称通常是唯一的。在一起,它们识别联系人提供程序和外部服务之间的特定数据流。
如果你想你的服务的数据传输到联系人提供商,你需要编写自己的同步适配器。此进行更详细的部分联系人提供同步适配器说明。
图4示出了联系人提供如何适合关于人的数据流。在框中标记为“同步适配器”,每个适配器是由它的帐户类型标记。
图4.数据的联系人提供流动。
所需的权限
要访问联系人提供商必须请求以下权限的应用程序:
读给一个或多个表的访问
READ_CONTACTS,在AndroidManifest.xml与作为<使用许可权的android:NAME =“android.permission.READ_CONTACTS”>的<使用许可权>元素中指定。
写入到一个或多个表的访问
WRITE_CONTACTS,在AndroidManifest.xml与作为<使用许可权的android:NAME =“android.permission.WRITE_CONTACTS”>的<使用许可权>元素中指定。
这些权限不延伸到用户配置文件数据。用户配置文件和其所需的权限是在以下部分,用户配置文件进行讨论。
请记住,用户的通讯录数据是个人和敏感。用户担心自己的隐私,所以他们不希望应用程序收集有关他们或他们的联系人数据。如果不是显而易见的,为什么你需要的权限访问他们的联系人数据,他们可以给你的应用程序收视率低或者干脆拒绝安装它。
用户配置文件
该ContactsContract.Contacts表具有包含该设备的用户简档数据的单一行。该数据描述了设备的用户,而不是用户的联系人中的一个。轮廓触头行链接到原始触点排为使用信息的每个系统。每个配置文件的原始接触行可以有多个数据行。用于访问用户配置文件中的常量的ContactsContract.Profile类是可用的。
访问用户配置文件需要特殊的权限。除了读取和写入所需的READ_CONTACTS和WRITE_CONTACTS权限,访问到用户配置文件需要读的android.Manifest.permission#READ_PROFILE和android.Manifest.permission#WRITE_PROFILE权限分别写访问。
请记住,你应该考虑用户的配置文件是敏感的。许可android.Manifest.permission#READ_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);注意:如果您检索多个联系人行,并要确定是否其中之一就是用户配置文件,测试排IS USER_PROFILE列。这列被设置为“1”,如果接触是用户简档。
联系方式供应商访问
本节介绍从联系人提供访问数据,重点对以下原则:
实体的查询。
批量修改。
检索和修改与意图。
数据的完整性。
从同步适配器进行修改也包括在部分联系人提供商同步适配器的详细信息。
查询实体
由于联系人提供的表中,用层级组织的,它往往是有用的检索行和所有链接到它的“子”行。例如,要显示一个人的所有信息,你可能要检索一个ContactsContract.RawContacts一行单一ContactsContract.Contacts行的所有ContactsContract.RawContacts行,或所有ContactsContract.CommonDataKinds.Email行。为了推动这项工作,联系人提供商提供了实体的结构,它像数据库表之间的联接。
实体就像一个从父表及其子表中选定列组成的表。当您查询一个实体,需要提供基于可从实体列投影和搜索条件。其结果是,包含光标包含该被检索每个子表行的一行。例如,如果您查询ContactsContract.Contacts.Entity联系人姓名和所有ContactsContract.CommonDataKinds.Email行针对该名称的所有原材料联系人,你回来包含一行每个ContactsContract.CommonDataKinds.Email行的光标。
实体简化查询。使用一个实体,你可以一次检索所有联系人或生接触接触的数据,而不必首先查询父表获得一个ID,然后不必查询子表与该ID。另外,联系人提供程序处理在一个事务,这确保了所检索的数据是内部一致的针对一个实体的查询。
注:通常实体不包含父和子表中的所有列。如果您尝试使用的列名,是不是在列名常量实体名单的工作,你会得到一个异常。
下面的代码片段展示了如何检索所有联系人的原始接触行。该片段是有两个活动,“主”和“细节”的一个更大的应用程序的一部分。主要活动显示联系人行的列表;当用户选择一个,该活动发送其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). */ mContactUri = Uri.withAppendedPath( mContactUri, ContactsContract.Contacts.Entity.CONTENT_DIRECTORY); // Initializes the loader identified by 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. mRawContactList.setAdapter(mCursorAdapter); ... @Override public Loader<Cursor> 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. */ 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. */ 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. */ return new CursorLoader( getApplicationContext(), // The activity's context mContactUri, // The entity content URI for a single contact projection, // The columns to retrieve null, // Retrieve all the raw contacts and their data rows. null, // sortOrder); // Sort by the raw contact ID. }当负载完成后,LoaderManager调用回调onLoadFinished()。之一的入参数这种方法是与查询结果的光标。在你自己的应用程序,你可以从该游标获取数据,以显示它或它的进一步工作。
// 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());接下来的代码片断创建的操作将原始联系行插入到表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. ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>(); /* * 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. */ 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());接下来,该代码创建的显示名称,电话和电子邮件行的数据行。
// Creates the display name for the new raw contact, as a StructuredName data row. 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(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to 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 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. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Phone .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 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. */ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0) // Sets the data row's MIME type to Email .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());最后一个片段显示)中插入新的原始联系人和数据行调用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. */ 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); } }批处理操作还允许您实现乐观并发控制,应用修改事务,而不必锁定底层存储库的方法。要使用此方法,你申请的事务,然后检查是否有可能在同一时间尚未做出其他修改。如果发现发生了不一致的修改,你回滚事务,重试。
/* * The application uses CursorLoader to query the raw contacts table. The system calls this method * when the load is finished. */ public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { // Gets the raw contact's _ID and VERSION values mRawContactID = cursor.getLong(cursor.getColumnIndex(BaseColumns._ID)); mVersion = cursor.getInt(cursor.getColumnIndex(SyncColumns.VERSION)); } ... // Sets up a Uri for the assert operation 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 ops = new ArrayList<ContentProviderOperationg>; ops.add(assertOp.build()); // You would add the rest of your batch operations to "ops" here ... // Applies the batch. If the assert fails, an Exception is thrown try { ContentProviderResult[] results = getContentResolver().applyBatch(AUTHORITY, ops); } catch (OperationApplicationException e) { // Actions you want to take if the assert operation fails go here }检索和修改与意图
// 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 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 */ // Defines an array list to contain the ContentValues objects for each row ArrayList<ContentValues> contactData = new ArrayList<ContentValues>(); /* * Defines the raw contact row */ // Sets up the row as a ContentValues object 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 phoneRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) 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 emailRow = new ContentValues(); // Specifies the MIME type for this data row (all data rows must be marked by their type) 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 */ 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);数据的完整性
contacts.xml参考
该文件contacts.xml包含控制您的同步适配器和应用程序与联系人应用程序和联系人提供的互动XML元素。这些元素在下面的章节中描述。
<联系人帐户类型>元素
在<联系人帐户类型>元素控制与联系人应用程序应用程序的交互。它的语法如下
<ContactsAccountType 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">包含在:
<ContactsDataKind android:mimeType="MIMEtype" android:icon="icon_resources" android:summaryColumn="column_name" android:detailColumn="column_name">包含在: