android联系人数据库介绍
- 格式:doc
- 大小:667.00 KB
- 文档页数:15
以下均是使用模拟器对Android 2.2系统联系人进行的分析。
系统联系人数据库存放在如下位置(data\data\com.android.providers.contacts\data bases\):数据库名为contacts2.db图 1使用SQLite Expert Professional打开该数据库,存在以下表:图 2其中有比较重要的三个表:data、raw_contacts、contacts。
一、三个重要的表1、data表data表中存放的是联系人具体信息,每行存储一位联系人的某个信息(如电话,姓名,邮箱等),结构如下:图 3data表建表语句如下:CREATE TABLE data (_id INTEGER PRIMARY KEY AUTOINCREMENT, 主键,每行IDpackage_id INTEGER REFERENCES package(_id),mimetype_id INTEGER REFERENCES mimetype(_id) NOT NULL, 引用表mimetypes,代表该行数据类型(The kind of data stored in a given row is specified by the row's MIMETYPE value, which determines the meaning of the generic columns DATA1 through DATA15)raw_contact_id INTEGER REFERENCES raw_contacts(_id) NOT NULL, 引用表raw_contacts,代表该数据所对应的联系人IDis_primary INTEGER NOT NULL DEFAULT 0,is_super_primary INTEGER NOT NULL DEFAULT 0,data_version INTEGER NOT NULL DEFAULT 0,data1 TEXT, 该行数据的主要信息,如电话号码,姓名等(DATA1 is an indexed column and should be used for the data element that is expected to be most frequently used in query selections.)data2 TEXT,data3 TEXT,data4 TEXT,data5 TEXT,data6 TEXT,data7 TEXT,data8 TEXT,data9 TEXT,data10 TEXT,data11 TEXT,data12 TEXT,data13 TEXT,data14 TEXT,data15 TEXT, data1-data15每项含义与mimetype_id有关data_sync1 TEXT,data_sync2 TEXT,data_sync3 TEXT,data_sync4 TEXT );data表触发器如下:CREATE TRIGGER data_updated AFTER UPDATE ON data BEGIN UPDATE data SET data_version=OLD.data_version+1 WHERE _id=OLD._id; UPDATE raw_contacts SET version=version+1 WHERE_id=OLD.raw_contact_id; END;CREATE TRIGGER data_deleted BEFORE DELETE ON data BEGIN UPDATE raw_contacts SET version=version+1 WHERE _id=OLD.raw_contact_id; DELETE FROM phone_lookup WHERE data_id=OLD._id; DELETE FROM status_updates WHERE status_update_data_id=OLD._id; DELETE FROM name_lookup WHERE data_id=OLD._id; END;目前模拟器中联系人如下:图 4图 6图 8数据库data表的数据如下:其中raw_contact_id值为3、5、6、8的行被标注,其对应的联系人为模拟器中的4个联系人:A(电话:1)、B(电话:2)、C(电话:3)、D-name2 D-name1(电话:123、456,住宅邮箱:email-home,住宅地址:Street City,Province postcode,组织:Whu,Stu),见图4―图8。
操作系统联系人现在很多App都可以对系统联系人进行操作,比如微信就可以直接将号码添加到系统联系人中,比如QQ 可以关联/备份/恢复系统联系人。
1.4.1准备知识通过DDMS,查看Android模拟器下的/data/data/com.android.providers.contacts/databases/包下的数据库(如图1-6所示),查看其contact2.db数据库的内容。
18图1-6 联系人数据库位置将contacts2.db 打开,观察其数据库内容,表结构有很多,但是我们主要关注其中的三张表即可。
其中raw_contacts 表存放的是联系人id 信息,一个联系人就是表中的一行记录;data 表中存放的是raw_contacts中的每一条id对应的具体信息,一个联系人可能有电话、邮件、姓名等多条信息,每一条信息在该表中都是一行记录;为了区分不同信息的类型,因此还有一个mimetypes表,该表存储的是常量数据,不同类型的信息由mimetype_id来标识。
raw_contacts 表:data 表:mimetypes 表:打开Android源码,查看packages\providers\路径下的文件,其中ContactsProvider就是联系人的内容提供者。
1.打开清单文件,寻找联系人的内容提供者对应的是哪个java 文件。
【文件1-11】1. <provider android:name="ContactsProvider2"192. android:authorities="contacts;com.android.contacts"3. android:label="@string/provider_label"4. android:multiprocess="false"5. android:readPermission="android.permission.READ_CONTACTS"6. android:writePermission="android.permission.WRITE_CONTACTS">7. <path-permission8. android:pathPrefix="/search_suggest_query"9. android:readPermission="android.permission.GLOBAL_SEARCH" />10.<path-permission11.android:pathPrefix="/search_suggest_shortcut"12.android:readPermission="android.permission.GLOBAL_SEARCH" />13.<path-permission14.android:pathPattern="/contacts/.*/photo"15.android:readPermission="android.permission.GLOBAL_SEARCH" />16.<grant-uri-permission android:pathPattern=".*"/>17.</provider>从清单文件可以看出,内容提供者的类名为ContactsProvider2.java,必须使用前需要添加如下权限:android:readPermission="android.permission.READ_CONTACTS"android:writePermission="android.permission.WRITE_CONTACTS">2.打开ContactsProvider2.java 文件,查看此内容提供者的uri 路径信息matcher.addURI(ContactsContract.AUTHORITY, "contacts",CONTACTS);matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_DATA);matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts",RAW_CONTACTS);matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#", RAW_CONTACTS_ID);matcher.addURI(ContactsContract.AUTHORITY, "raw_contacts/#/data", RAW_CONTACTS_DATA);3.根据源码,确定内容提供者的Uri 信息为:操作raw_contacts表的Uri:content://com.android.contacts/raw_contacts操作data表的Uri:content://com.android.contacts/data4.操作数据库表时注意事项由于contacts2.db数据库使用了视图,所以操作数据库表时,看到的表字段名称和真实操作的有所不同。
Android联系⼈Contacts详解1.获取联系⼈详细信息在(⼀)中我们只是获取了联系⼈的ID和NAME,但是这是远远不够的,怎么样获取其他的值呢?public void fetchContactInformation() {String id,name,phoneNumber,email;ContentResolver contentResolver = this.getContentResolver();Cursor cursor = contentResolver.query(android.provider.ContactsContract.Contacts.CONTENT_URI,null, null, null, null);while(cursor.moveToNext()) {id=cursor.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts._ID));name=cursor.getString(cursor.getColumnIndex(android.provider.ContactsContract.Contacts.DISPLAY_NAME));//Fetch Phone NumberCursor phoneCursor = contentResolver.query(monDataKinds.Phone.CONTENT_URI,null, monDataKinds.Phone.CONTACT_ID+"="+id, null, null);while(phoneCursor.moveToNext()) {phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(monDataKinds.Phone.NUMBER));System.out.println("id="+id+" name="+name+" phoneNumber="+phoneNumber);}phoneCursor.close();//Fetch emailCursor emailCursor = contentResolver.query(monDataKinds.Email.CONTENT_URI,null, monDataKinds.Email.CONTACT_ID+"="+id, null, null);while(emailCursor.moveToNext()) {email = emailCursor.getString(emailCursor.getColumnIndex(monDataKinds.Email.DATA));System.out.println("id="+id+" name="+name+" email="+email);}emailCursor.close();}cursor.close();}结果:11-06 14:38:32.049: I/System.out(26534): id=4 name=张三 phoneNumber=1-234-5611-06 14:38:32.138: I/System.out(26534): id=5 name=李四 phoneNumber=654-32111-06 14:38:32.138: I/System.out(26534): id=5 name=李四 phoneNumber=987-654-32111-06 14:38:32.188: I/System.out(26534): id=5 name=李四 email=wssiqi@在这⾥,我们通过android.provider.ContactsContract.Contacts.CONTENT_URI 来获取联系⼈的ID和NAMEmonDataKinds.Phone.CONTENT_URI 获取联系⼈的电话号码monDataKinds.Email.CONTENT_URI 获取联系⼈的邮箱地址关键是ContactsContract下⾯有很多类,很不容易找到到底哪个类包含我们需要的内容。
大唐移动通信设备有限公司是国家大型高科技央企——大唐电信科技产业集团的核心企业,是我国拥有自主知识产权的第三代移动通信标准TD—SCDMA的提出者、核心技术的开发者及产业化的推动者。
拥有第三代国际移动通信标准TD—SCDMA及其后续演进的TD—LTE的关键技术核心知识产权,在TDD制式领域中,大唐移动的全球标准提案数量及通过率均为世界第一,其主导的TD—LTE—Advanced已被国际电联接纳为4G标准候选技术。
android中的数据库操作android中的应用开发很难避免不去使用数据库,这次就和大家聊聊android中的数据库操作。
一、android内的数据库的基础知识介1.用了什么数据库android中采用的数据库是SQLite这个轻量级的嵌入式开源数据库,它是用c 语言构建的。
相关简介可以从链接查看。
2.数据库基本知识观花对于一些和我一样还没有真正系统学习数据库技术的同学来说,把SQL92标准中的一些基本概念、基本语句快速的了解一下,是很有必要的,这样待会用Android的database相关方法去执行一些数据库语句时就不会茫然了。
①数据库的基本结构——表格表格是数据库中储存资料的基本架构。
表格被分为栏位(column) 及列位(row)。
每一列代表一笔资料,而每一栏代表一笔资料的一部份。
举例来说,如果我们有一个记载顾客资料的表格,那栏位就有可能包括姓、名、地址、城市、国家、生日...等等。
每一个表格拥有一个独一无二的名字(Table Name)以便能够让用户定位到它上面。
一个典型的表格结构如下:Store_Information 表格store_name Sales DateLos Angeles $1500 Jan-05-1999San Diego $250 Jan-07-1999Los Angeles $300 Jan-08-1999Boston $700 Jan-08-1999该表格的表格名字为Store_Information,一共有三个栏位,分别为store_name , Sales , Data ,已经录入了四笔数据所以有四个列位。
android sqlite数据库原理1. 引言1.1 概述在移动应用开发中,使用数据库是非常常见的需求之一。
Android平台提供了一种轻量级的数据库引擎,即SQLite。
SQLite是一种嵌入式关系型数据库管理系统,它以小型、快速和可靠的特点而受到广泛应用。
本篇文章将介绍Android中使用SQLite数据库的原理和相关知识。
我们将深入探讨数据库基础知识,以及了解SQLite在Android平台中的应用。
通过对SQLiteOpenHelper类的解析,我们可以学习如何创建和更新数据库,并执行SQL操作和查询数据。
此外,我们还将探讨关于数据库事务管理和性能优化方面的内容。
了解事务管理概述以及增加性能的技巧与注意事项将帮助我们设计更高效的数据库操作。
最后,在结论部分,我们将总结主要观点和所获得的结果,并对未来在Android 开发中使用SQLite数据库提出展望和建议。
1.2 文章结构本文分为五个主要部分:- 引言:介绍本文主题和目标。
- Android SQLite数据库原理:阐述数据库基础知识、SQLite简介和SQLite 操作流程。
- Android中的SQLite数据库应用:讲解SQLiteOpenHelper类、创建和更新数据库,以及执行SQL操作和查询数据。
- 数据库事务管理和性能优化:探讨事务管理概述、增加性能的技巧与注意事项,以及避免常见错误和陷阱的方法。
- 结论:总结主要观点和发现结果,提出对未来的展望和建议。
1.3 目的本文的目的是帮助读者全面了解Android平台中使用SQLite数据库的原理和应用。
通过深入研究数据库基础知识、SQLite引擎以及在Android中操作数据库的流程,读者将能够更好地应用SQLite数据库进行数据存储和查询。
此外,通过学习数据库事务管理和性能优化方面的内容,读者将获得设计高效数据库操作的指导,并避免一些常见错误和陷阱。
通过本文的阐述,读者将可以从理论到实践地掌握Android平台中使用SQLite 数据库所需的知识和技术,并为未来在移动应用开发中构建更稳定、高效、可靠的数据库功能提供指导。
Android开发之获得通讯录及SIM卡中联系人Android手机的通讯录联系人全部都存在系统的数据库中,如果须要获得通讯里联系人的信息就须要访问系统的数据库,才能将信息拿出来。
这一篇文章我主要带领同学们熟悉Android的通讯录机制。
图中选中的数据库 contacts2.db就是系统储存联系人的数据库,我们将它打开看看里面储存了些什么东东?打开contacts.db后发面里面有一堆表,同学们先别慌张。
今天我们主要讨论红框内的4个比较常用的表,后期我在介绍其它表的使用。
这里说一下如果你想在真机上查看数据库的话必需要先获得root权限,否则无法查看。
1.contacts 表_id :表的ID,主要用于其它表通过contacts 表中的ID可以查到相应的数据。
display_name: 联系人名称photo_id:头像的ID,如果没有设置联系人头像,这个字段就为空times_contacted:通话记录的次数last_time_contacted: 最后的通话时间lookup :是一个持久化的储存因为用户可能会改名子但是它改不了lookup2.data表raw_contact_id:通过raw_contact_id可以找到 raw_contact表中相对的数据。
data1 到 data15 这里保存着联系人的信息联系人名称联系人电话号码电子邮件备注等等。
3.phone_look_up表data_id : 通过data_id可以找到 datat表中相对的数据。
raw_contact_id : 通过raw_contact_id 可以找到 raw_contact_表中相对的数据。
normalized_number: 这个字段就比较有意思了,它是将每个电话号码逆序排列。
4.raw_contact表version :版本号,用于监听变化deleted :删除标志, 0为默认 1 表示这行数据已经删除display_name : 联系人名称last_time_contacts : 最后联系的时间有关这些的源码都在android.provider.ContactsContract这个类里面,如果想深入了解的话可以去看看,数据库相关的操作联查啊啥的都在里面。
Android学习——数据库简介
SQLite数据库
⼀、SQLite数据库简介
(1)SQLite数据库是⼀个开源的嵌⼊式关系数据库。
(2)特点:
更加适⽤于嵌⼊式系统,嵌⼊到使⽤它的应⽤程序中去。
占⽤⾮常少的内存,运⾏⾼效可靠,可移植性好。
提供了零配置运⾏模式。
屏蔽了数据库使⽤和管理的复杂性,程序仅需进⾏最基本的数据操作,其他操作可以交给进程内部的数据库引擎完成。
使⽤模块化设计由⼋个独⽴的模块构成,这些独⽴模块⼜构成了三个主要的⼦系统。
接⼝由SQLite C API组成,因此⽆论是应⽤程序、脚本,还是库⽂件,最终都是通过接⼝与SQLite交互。
核⼼代码有C编写,⼤概有三万多⾏。
综上,我们可以对SQLite数据库有个⼤概的了解,并应该知道安卓开发中使⽤该数据库的原因。
学习过其他数据库的同学应该知道,对数据的操作包括两种,有代码的动态操作,和命令⾏的直接操作。
当然SQLite数据库的命令⾏操作不是重点我们就⼤概的讲解⼀下怎么进⼊吧,后续操作跟⼀般数据库的相似。
⼆、SQLite数据库的命令⾏操作
⾸先,讲解⼀下SQLite数据库⾃带的⼀个基于命令⾏的SQL命令执⾏⼯具——sqlite3。
sqlite3⼯具被集成在Android系统中,⽤户在Linux的命令⾏界⾯中输⼊sqlite3,启动。
启动Linux的命令⾏界⾯的⽅法是在CMD中打开你在安卓中下载SDK的地址,在打开SDK下的flatform-tools⽬录,输⼊adb shell命令,可进⼊。
<联系人>联系人数据库介绍拟制: Prepared by 吕欣阳日期:Date2015-11-26审核: Reviewed by 日期:Dateyyyy-mm-dd审核: Reviewed by 日期:Dateyyyy-mm-dd批准: Granted by日期:Dateyyyy-mm-dd青岛海信移动技术股份有限公司版权所有侵权必究修订记录Revision record目录联系人数据库介绍 (1)1 关键类 (1)1.1 ContactAggregator.java (1)1.2 MoreDatabaseUtils.java (1)1.3 ContactsDumpActivity.java (1)1.4 CallLogProvider.java (2)1.5 ContactLocaleUtils.java (2)1.6 ContactsDatabaseHelper.java (3)1.7 ContactsProvider2.java (4)1.8 DataRowHandler.java (5)1.9 FastScrollingIndexCache.java (5)1.10 GlobalSearchSupport.java (6)1.11 HanziToPinyin.java (6)1.12 NameSplitter.java (6)1.13 PhotoProcessor.java (6)1.14 SearchIndexManager.java (6)2 数据库主要表介绍 (7)2.1 Accounts表 (7)2.2 Contacts表 (7)2.3 data表 (7)2.4 groups表 (8)2.5 mimetypes表 (8)2.6 name_lookup表 (8)2.7 phone_lookup表 (8)2.8 raw_contacts表 (9)2.9 search_index_content表 (9)3 phone_lookup查询介绍 (10)4 私密联系人实现 (10)5 sqlite3介绍 (11)联系人数据库介绍1 关键类1.1 ContactAggregator.java合并、拆分类,两个联系人可以合并为一个,合并后详情显示全部信息,编辑界面可以看到合并的多个记录;合并后记录可以拆分为合并之前的多个记录对于contacts表的操作也在这个类中,contacts表中数据的生成在computeAggregateData()函数中。
1.2 MoreDatabaseUtils.java类中有dumpCursor函数可以输出cursor中的所有数据,不支持输出blob图片数据,有异常,原始的bug1.3 ContactsDumpActivity.java导出数据库问题类,属于后门,可以将用户手机中联系人数据库通过电子邮件方式分享出来,可以用于调查问题。
使用方法:在列表搜索框中输入debug debug!,按menu导出数据库文件1.4 CallLogProvider.java通话记录数据库操作类1.5 ContactLocaleUtils.java1.生成raw_contacts表中phonebook_label和phonebook_bucket这两个字段表示联系人记录在哪个英文字母下显示,比如b开头的中文都显示先B 下,列表记录显示查询时通过对phonebook_label加group by,对phonebook_bucket 加order by;阿拉伯语也会生成阿语相应的字段Vision风格右边显示的ABCD,滑动到置顶字母下也用这两个字段2.用户生成搜索数据新建记录时通过该类中getPinyinNameLookupKeys接口生成,只会生成简拼和全拼,比如滑动,会生成dong、huadong、d、hd、滑动,在转码,放在search_index_content表中,检索时会搜索这个表。
1.6 ContactsDatabaseHelper.java数据库创建,表、视图createContactsViews、索引createContactsIndexes、触发器createContactsTriggers的创建,数据库版本的升级;1.删除一个联系人的时候,删除了raw_contacts和contacts表,data表的内容通过触发器删除。
db.execSQL("CREATE TRIGGER " + Tables.RAW_CONTACTS + "_deleted "+ " BEFORE DELETE ON " + Tables.RAW_CONTACTS+ " BEGIN "+ " DELETE FROM " + Tables.DATA+ " WHERE " + Data.RAW_CONTACT_ID+ "=OLD." + RawContacts._ID + ";"+ " DELETE FROM " + Tables.AGGREGATION_EXCEPTIONS+ " WHERE " + AggregationExceptions.RAW_CONTACT_ID1+ "=OLD." + RawContacts._ID+ " OR " + AggregationExceptions.RAW_CONTACT_ID2+ "=OLD." + RawContacts._ID + ";"+ " DELETE FROM " + Tables.VISIBLE_CONTACTS+ " WHERE " + Contacts._ID + "=OLD." + RawContacts.CONTACT_ID+ " AND (SELECT COUNT(*) FROM " + Tables.RAW_CONTACTS+ " WHERE " + RawContacts.CONTACT_ID + "=OLD." + RawContacts.CONTACT_ID+ " )=1;"+ " DELETE FROM " + Tables.DEFAULT_DIRECTORY+ " WHERE " + Contacts._ID + "=OLD." + RawContacts.CONTACT_ID+ " AND (SELECT COUNT(*) FROM " + Tables.RAW_CONTACTS+ " WHERE " + RawContacts.CONTACT_ID + "=OLD." + RawContacts.CONTACT_ID+ " )=1;"+ " DELETE FROM " + Tables.CONTACTS+ " WHERE " + Contacts._ID + "=OLD." + RawContacts.CONTACT_ID+ " AND (SELECT COUNT(*) FROM " + Tables.RAW_CONTACTS+ " WHERE " + RawContacts.CONTACT_ID + "=OLD."+ RawContacts.CONTACT_ID+ " )=1;"+ " END");2.修改数据库字段、视图的时候,一定要升级数据库版本,防止ota升级导致异常,升级时最好包括数据的升级。
1.7 ContactsProvider2.java1.与数据库交互的类,查询、增删改;2. 文件的开头已经定义好了支持查询的所有urifinal UriMatcher matcher = sUriMatcher;matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_ID_DATA);matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID);…….所有支持查询的uri放在sUriMatcher变量中,应用查询时,通过match()函数返回变量具体查询的流程final int match = sUriMatcher.match(uri);switch (match) {case SYNCSTA TE:case PROFILE_SYNCSTATE:}返回的match就是addURI的第三个参数。
3.addURI时,第二个参数中的*和#的函数可以通过具体实现理解matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#", CONTACTS_LOOKUP_ID);addURI() {….if (token.equals("#")) {child.mWhich = NUMBER;} else if (token.equals("*")) {child.mWhich = TEXT;} else {child.mWhich = EXACT;}….}可以看到#代表数字,*代表字母,其他的必须要完全一样比如matcher.addURI(ContactsContract.AUTHORITY, "contacts/lookup/*/#/entities",CONTACTS_LOOKUP_ID_ENTITIES);和uri = content://com.android.contacts/contacts/lookup/1873r217-141A16/216/entities可以匹配上1.8 DataRowHandler.javadata表操作类,对data表增删改操作的类派生的类有:DataRowHandlerForCommonDataKind.javaDataRowHandlerForCustomMimetype.javaDataRowHandlerForEmail.java --对email的操作DataRowHandlerForGroupMembership.javaDataRowHandlerForIdentity.javaDataRowHandlerForIm.java --对IM的操作DataRowHandlerForNickname.java –对昵称的操作DataRowHandlerForNote.java 备注DataRowHandlerForOrganization.java—组织DataRowHandlerForPhoneNumber.java—号码DataRowHandlerForPhoto.java—大头贴DataRowHandlerForStructuredName.java—姓名DataRowHandlerForStructuredPostal.java—地址比如修改记录,添加一个号码,会调用ContactsProvider的insert操作,再调用DataRowHandlerForPhoneNumber.java把号码写到data表1.9 FastScrollingIndexCache.java存放查询的缓存,用于获取记录所在的ABCD字母数据public static final Bundle buildExtraBundle(String[] titles, int[] counts) { Bundle bundle = new Bundle();bundle.putStringArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES, titles);bundle.putIntArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS, counts);return bundle;}EXTRA_ADDRESS_BOOK_INDEX_TITLES是字母索引,EXTRA_ADDRESS_BOOK_INDEX_COUNTS 是个数11-26 14:28:35.409 I/ContactsProvider(18671): labels[0]=# counts[0]=711-26 14:28:35.409 I/ContactsProvider(18671): labels[1]=B counts[1]=411-26 14:28:35.410 I/ContactsProvider(18671): labels[2]=C counts[2]=211-26 14:28:35.410 I/ContactsProvider(18671): labels[3]=D counts[3]=111-26 14:28:35.410 I/ContactsProvider(18671): labels[4]=E counts[4]=111-26 14:28:35.410 I/ContactsProvider(18671): labels[5]=F counts[5]=211-26 14:28:35.410 I/ContactsProvider(18671): labels[6]=G counts[6]=511-26 14:28:35.410 I/ContactsProvider(18671): labels[7]=H counts[7]=411-26 14:28:35.410 I/ContactsProvider(18671): labels[8]=J counts[8]=611-26 14:28:35.410 I/ContactsProvider(18671): labels[9]=K counts[9]=511-26 14:28:35.410 I/ContactsProvider(18671): labels[10]=L counts[10]=211-26 14:28:35.410 I/ContactsProvider(18671): labels[11]=M counts[11]=111-26 14:28:35.410 I/ContactsProvider(18671): labels[12]=N counts[12]=111-26 14:28:35.411 I/ContactsProvider(18671): labels[13]=T counts[13]=12 11-26 14:28:35.411 I/ContactsProvider(18671): labels[14]=W counts[14]=111-26 14:28:35.411 I/ContactsProvider(18671): labels[15]=X counts[15]=2这两个值用于生成ContactsSectionIndexer,快速定位用的,比如点击快速定位的C,能快速定位到C开头的第一个字母,即#开头的个数+A开头的个数+B开头的个数。