10.Android通讯录-联系人查询

相关内容:

  1. 联系人数据库结构
  2. 内容提供者(略)

官方文档:https://developer.android.com/guide/topics/providers/contacts-provider.html

1.数据库结构

相关表共三个:Contacts、RawContacts、Data

1.ContactsContract.Contacts 原始联系表
---- URI: ContactsContract.Contacts.CONTENT_URI
表示不同联系人的行,基于聚合的原始联系人行。

字段说明:
1.Contacts.CONTENT_DIRECTORY | Constant Value:"photo"         |
2.Contacts.DISPLAY_PHOTO:    | Constant Value:"display_photo" | 全尺寸照片
3.Contacts.PHOTO:            | Constant Value:"data15"        | 照片缩略图
4.Contacts.PHOTO_FILE_ID:    | Constant Value:"data14"        | 全尺寸照片的文件ID (用此查询,See: ContactsContract.DisplayPhoto)

2.ContactsContract.RawContacts联系人数据摘要表
---- URI: ContactsContract.RawContacts.CONTENT_URI
包含联系人数据摘要的行,针对特定用户帐户和类型。

字段说明:
1.RawContacts._ID  - long                |  id   不解释 ,永远唯一
2.RawContacts.CONTACT_ID  - long
3.RawContacts.AGGREGATION_MODE - int
4.RawContacts.DELETED - int              |  是否删除  0:正常 , 1:删除
5.RawContacts.TIMES_CONTACTED  - int     |  联系的次数
6.RawContacts.LAST_TIME_CONTACTED - long |  最近联系时间
7.RawContacts.STARRED -int               |  是否是常用联系人  0:不是 ,1:是
8.RawContacts.CUSTOM_RINGTONE  - String  |  自定义铃声
9.RawContacts.SEND_TO_VOICEMAIL - int    |  是否使用语音信息  0:不是 ,1:是
10.RawContacts.ACCOUNT_NAME - String     |  账户名称 与ACCOUNT_TYPE对应
11.RawContacts.ACCOUNT_TYPE  - String    |  账户类型 比如:Gmail 
12.RawContacts.DATA_SET - String         |  账户数据
13.RawContacts.SOURCE_ID - String        |   
14.RawContacts.VERSION - int             |  当前版本号
15.RawContacts.DIRTY - int               |  标记此条记录是否更改过

3.ContactsContract.Data 联系人详细信息表
---- URI: ContactsContract.Data.CONTENT_URI 或 ContactsContract.Phone.CONTENT_URI
包含原始联系人详细信息(例如电子邮件地址或电话号码)的行。

字段说明:
1.Data._ID - long             
2.Data.MIMETYPE - String       |  数据类型,详细见下段
3.Data.RAW_CONTACT_ID - long   |  同RawContacts.CONTACT_ID  
4.Data.IS_PRIMARY - int        |  标记重要  0 or 1
5.Data.IS_SUPER_PRIMARY - int  |  默认使用此条数据 0 or 1
6.Data.DATA_VERSION  - int     |  数据版本
7.Data.Data1                   |  与MIMETYPE有关,当为Phone.CONTENT_ITEM_TYPE时,Data1 就是电话号码
8.Data.Data2~~Data.Data15     

2.Data.MIMETYPE  参数列表 : 
StructuredName.CONTENT_ITEM_TYPE
Phone.CONTENT_ITEM_TYPE
Email.CONTENT_ITEM_TYPE
Photo.CONTENT_ITEM_TYPE
Organization.CONTENT_ITEM_TYPE
Im.CONTENT_ITEM_TYPE
Nickname.CONTENT_ITEM_TYPE
Note.CONTENT_ITEM_TYPE
StructuredPostal.CONTENT_ITEM_TYPE
GroupMembership.CONTENT_ITEM_TYPE
Website.CONTENT_ITEM_TYPE
Event.CONTENT_ITEM_TYPE
Relation.CONTENT_ITEM_TYPE
SipAddress.CONTENT_ITEM_TYPE

2.查询联系人列表

知道表结构后就可以很快的查取数据了,这里不讲内容提供者如何查询,直接上代码
重点在getContactsList() 和 getContactList() 两个方法
getContactsList() 返回数据结构:ContactsBean(String name, List<String> number)的List集合
getContactList() 返回数据结构 :ContactBean(String name, String number)的List集合

  • 看情况选择:getContactsList() 数据结构清晰 ,getContactList() 速度快

查询到数据后应注意:

  1. 查询后的联系人姓名可能为空
  2. 查询后的电话号码可能有空格
  3. 查询后的电话号码可能为空
  4. 查询后的电话号码可能不是数字
    下面代码已经做了相应处理, 代码仅供参考,暂不考虑性能,自行优化(静态Bean类)

获取联系人列表流程

  1. 通过ContentResolver查询数据库, Uri可根据上表合理选择(此处选择Contacts表的uri),得到返回的cusor
  2. 遍历cusor获取所有的联系人姓名
  3. 根据联系人姓名查询其拥有的联系电话(不止一个),(此处选择Data表)
public static List<ContactsBean> getContactsList(Context context) {
        Logger.d("SMSHelper", "-----------SMSHelper#getContactsList()----------");
        Logger.d("SMSHelper", "开始查询 Contacts 表");
        List<ContactsBean> list = new ArrayList<ContactsBean>();
        ContactsBean bean = null;
        ContentResolver resolver = context.getContentResolver();
        Cursor cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

        if (cursor == null && cursor.getCount() <= 0) {
            return null;
        }
        Logger.d("SMSHelper", "cursor.getCount():" + cursor.getCount());

        while (cursor.moveToNext()) {
            bean = new ContactsBean();

            String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));//姓名

            wirteNumbers(resolver, name, bean);
            list.add(bean);
        }
        cursor.close();
        return list;
    }

   /**
     * 根据联系人姓名查询电话
     * 并写入
     */
    private static void wirteNumbers(final ContentResolver contentResolver, String name, final ContactsBean bean) {
        Logger.d("SMSHelper", "开始查询 Data 表 : 查询联系人:" + name);
        Cursor dataCursor = contentResolver.query(ContactsContract.Data.CONTENT_URI,
                new String[]{ContactsContract.Data.DATA1},
                ContactsContract.Data.DISPLAY_NAME + "= ? ",
                new String[]{name}, null);
        if (dataCursor == null) {
            Logger.w("SMSHelper", "dataCursor == null ");
            return;
        }
        if (dataCursor.getCount() > 0) {
            bean.setName(name);
            Logger.w("SMSHelper", " 电话信息 -- size: " + dataCursor.getCount());
            while (dataCursor.moveToNext()) {
                String number = dataCursor.getString(dataCursor.getColumnIndex(ContactsContract.Data.DATA1));
                if (TextUtils.isEmpty(number) || !TextUtils.isDigitsOnly(number = number.replace(" ", ""))) {
                    Logger.w("SMSHelper", " 电话信息(异常) -- number: " + number);
                    continue;
                }
                bean.getNumList().add(number);
                Logger.w("SMSHelper", " 电话信息 -- number: " + number);
            }
            dataCursor.close();
        } else {
            Logger.w("SMSHelper", " 无电话信息 -- name: " + name);
        }
        return;
    }

完整代码

package app.utils;

import java.util.ArrayList;
import java.util.List;

import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.telephony.SmsManager;
import android.text.TextUtils;

import com.google.common.collect.Lists;

/**
 * 短信电话相关工具类<br/>
 * 目录: <br/>
 * 1.发送短信 sendSMS() <br/>
 * 2.拨打电话短信 callPhone() <br/>
 * 3.获取所有短信记录getAllSms() <br/>
 * 4.获取所有联系人getContactsList() <br/>
 * 5.获取所有联系人getContactList() : 与第4条所生成的数据结构不同 <br/>
    
 * <b>注</b>:使用时请添加相关权限
 *
 * @author 赵LW QQ:739043667
 */
public class SMSHelper {

    /**
     * 发送短信 (需要权限SMS_Send)
     *
     * @param num  电话
     * @param text 短信内容
     */
    public static void sendSMS(String num, String text) {
        SmsManager.getDefault().sendTextMessage(num, null, text, null, null);
    }

    public static void callPhone(Context context, String num) {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_CALL);
        intent.setData(Uri.parse("tel:" + num));
        // 开启系统拨号器
        context.startActivity(intent);
    }

    /**
     * 获取所有联系人 需要权限
     * <uses-permission android:name="android.permission.READ_CONTACTS" />
     * 数据结构:ContactBean(String displayName, String numList)
     *
     * @param
     * @return
     */
    public static List<ContactBean> getContactList(Context context) {

        Logger.d("SMSHelper", "-----------SMSHelper#getContactList()----------");
        Logger.d("SMSHelper", "开始查询 Data 表");
        List<ContactBean> list = new ArrayList<ContactBean>();

        ContactsContract.Data._ID
        ContentResolver resolver = context.getContentResolver();
        Cursor cursor = resolver.query(ContactsContract.Data.CONTENT_URI, null, null, null, null);

        if (cursor == null && cursor.getCount() <= 0) {
            return null;
        }
        Logger.d("SMSHelper", "cursor.getCount():" + cursor.getCount());

        while (cursor.moveToNext()) {

            String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME));
            String number = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.DATA1));

            //数据清洗
            if (TextUtils.isEmpty(number)) {
                continue;
            }
            if (!TextUtils.isDigitsOnly(number = number.replace(" ", ""))) {
                continue;
            }

            if (TextUtils.isEmpty(name)) {
                name = number;
            }
            list.add(new ContactBean(name, number));
        }
        cursor.close();
        return list;
    }

    /**
     * 获取所有联系人
     * 数据结构:ContactsBean(String displayName, List<String> numList)
     * <p/>
     * 需要权限:
     * <uses-permission android:name="android.permission.READ_CONTACTS" />
     *
     * @param
     * @return List<ContactsBean>
     */
    public static List<ContactsBean> getContactsList(Context context) {

        Logger.d("SMSHelper", "-----------SMSHelper#getContactsList()----------");
        Logger.d("SMSHelper", "开始查询 Contacts 表");
        List<ContactsBean> list = new ArrayList<ContactsBean>();
        ContactsBean bean = null;
        ContentResolver resolver = context.getContentResolver();
        Cursor cursor = resolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

        if (cursor == null && cursor.getCount() <= 0) {
            return null;
        }
        Logger.d("SMSHelper", "cursor.getCount():" + cursor.getCount());

        while (cursor.moveToNext()) {
            bean = new ContactsBean();

            String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));//姓名

            wirteNumbers(resolver, name, bean);
            list.add(bean);
        }
        cursor.close();
        return list;
    }

    /**
     * 根据联系人姓名查询电话
     * 并写入
     */
    private static void wirteNumbers(final ContentResolver contentResolver, String name, final ContactsBean bean) {
        Logger.d("SMSHelper", "开始查询 Data 表 : 查询联系人:" + name);

        Cursor dataCursor = contentResolver.query(ContactsContract.Data.CONTENT_URI,
                new String[]{ContactsContract.Data.DATA1},
                ContactsContract.Data.DISPLAY_NAME + "= ? ",
                new String[]{name}, null);
        if (dataCursor == null) {
            Logger.w("SMSHelper", "dataCursor == null ");

            return;
        }
        if (dataCursor.getCount() > 0) {
            bean.setName(name);
            Logger.w("SMSHelper", " 电话信息 -- size: " + dataCursor.getCount());
            while (dataCursor.moveToNext()) {
                String number = dataCursor.getString(dataCursor.getColumnIndex(ContactsContract.Data.DATA1));

                if (TextUtils.isEmpty(number) || !TextUtils.isDigitsOnly(number = number.replace(" ", ""))) {
                    Logger.w("SMSHelper", " 电话信息(异常) -- number: " + number);
                    continue;
                }
                bean.getNumList().add(number);
                Logger.w("SMSHelper", " 电话信息 -- number: " + number);
            }
            dataCursor.close();
        } else {
            Logger.w("SMSHelper", " 无电话信息 -- name: " + name);
        }
        return;
    }

    /**
     * 获取短信记录 (需要bean: Smsinfo.java和 Read_SMS权限)
     * <p>
     * <uses-permission android:name="android.permission.READ_SMS" />
     *
     * @return List<Smsinfo>
     * @author zlw QQ:739043667
     */
    public static List<SmsInfo> getAllSms(Context context) {
        List<SmsInfo> smsinfos = new ArrayList<SmsInfo>();

        Uri uri = Uri.parse("content://sms/");
        ContentResolver resolver = context.getContentResolver();
        Cursor cursor = resolver.query(uri, new String[]{"address", "date", "type", "body"}, null, null, null);

        SmsInfo smsinfo = null;
        while (cursor.moveToNext()) {
            String address = cursor.getString(0);
            String date = cursor.getString(1);
            String type = cursor.getString(2);
            String body = cursor.getString(3);
            smsinfo = new SmsInfo(address, date, type, body);
            smsinfos.add(smsinfo);
        }

        cursor.close();
        return smsinfos;
    }

    /**
     * 短信信息Bean 类
     *
     * @param
     * @author zlw QQ:739043667
     * @return
     */
    public static class SmsInfo {
        String address;
        String date;
        String type;
        String body;

        public SmsInfo(String address, String date, String type, String body) {
            super();
            this.address = address;
            this.date = date;
            this.type = type;
            this.body = body;
        }

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        public String getDate() {
            return date;
        }

        public void setDate(String date) {
            this.date = date;
        }

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

        public String getBody() {
            return body;
        }

        public void setBody(String body) {
            this.body = body;
        }

    }

    /**
     * 联系人集合Bean类
     */
    public static class ContactsBean {

        private String name;
        private List<String> numList;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public List<String> getNumList() {
            return numList;
        }

        public void setNumList(List<String> numList) {
            this.numList = numList;
        }

        public ContactsBean() {
            numList = Lists.newArrayList();
        }

        public ContactsBean(String displayName, List<String> numList) {
            super();
            this.name = displayName;
            if (numList == null) {
                this.numList = Lists.newArrayList();
            } else {
                this.numList = numList;
            }
        }

        @Override
        public String toString() {
            return "ContactsBean [name=" + name + ", numList=" + numList + "]";
        }
    }


    /**
     * 联系人Bean类
     */
    public static class ContactBean {

        private String name;
        private String number;

        public ContactBean() {
        }

        public ContactBean(String name, String number) {
            this.name = name;
            this.number = number;
        }

        public String getName() {
            return name;
        }

        @Override
        public String toString() {
            return "ContactBean{" +
                    "name='" + name + '\'' +
                    ", number='" + number + '\'' +
                    '}';
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getNumber() {
            return number;
        }

        public void setNumber(String number) {
            this.number = number;
        }
    }

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容