android 车机电话的通讯录联系人搜索实现解析 ------- 填坑日记

Posted Fresh_Air_Life

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了android 车机电话的通讯录联系人搜索实现解析 ------- 填坑日记相关的知识,希望对你有一定的参考价值。

项目中的android 车机系统 搜索联系人算法一直有问题 , 这里就把整个的流程写一遍

 

一 . 搜索算法实现的功能

1.支持中文,英文搜索

2.支持电话号码搜索

3.支持汉语拼音搜索, 首字母搜索也能支持, 同时对检索到的文字显示高亮

前面的第一, 第二点, 都是比较简单的, 通过遍历字符串, 查看字符串是否包含用户输入的字符, 就能达到检索的功能

重点是第三点,拼音的搜索,首字母搜索

 

二. 拼音搜索的流程

1.先介绍几个类

ContactData.java , 里面保存有手机端同步过来的数据
public class ContactData implements Serializable, Parcelable 
    public static final int CONTACT_NAME_MAX_LENGTH = 16;
    public static final int CONTACT_PHONE_MAX_LENGTH = 32;
    private String name = "";
    private String letter = "";

    private List<Integer> phoneNumTypeList = new ArrayList<>();

    private List<String> phoneNumList = new ArrayList<>();

    public List<NumberData> numbers = new ArrayList<>();

    private List<String> addressList = new ArrayList<>();

    public int photoType;
    public byte[] photoBytes;

     ....  //一些可能用到的方法

SearchResult.java  , 搜索结果实体类 . 
public class SearchResult implements Serializable, Cloneable, Parcelable 
    private static final long serialVersionUID = -8624630249543035384L;

    public long contactID = -1;

    public String name = "";

    public String phone;
    public String time;
    public int count = 1;
    // 加入优先级 排序用的
    int priority = -1;
    public String pinyin;

    public String number;
    public String initials;
    public String pinyinInitials;

    // 高亮
    public String[] highlight;
    // 分解
    ArrayList<PyNode> nodes;

    public int photoType;
    public byte[] photoBytes;

    ...// 一些可能使用到的方法

Pinyin.java 这个类来自于开源的项目 com.github.promeg.pinyinhelper , 通过下面的语句,可以将中文转化为拼音, 具体的原理, 不详,有时间再看看

            // 汉字
            String pinyin = Pinyin.toPinyin(c);

 

 

2.实现流程, 

a.先将同步到的联系人数据contacts 转为searchResult 数据,  这个过程就是将名字数据转换为拼音,  生成首字母数据pinyinInitials 

    private List<SearchResult> convertFormatSearchResult(List<ContactData> contactsList) 
        Lg.i(TAG, " convertFormatSearchResult ");
        if (contactsList == null || contactsList.isEmpty()) 
            return Lists.newArrayList();
        

        List<SearchResult> searchResults = new ArrayList<>();

        String phoneNumber;
        String name;

        String tempKey = null;
        for (ContactData phones : contactsList) 

            int size = phones.numbers.size();
            for (int i = 0; i < size; i++) 
                name = phones.getName();
                phoneNumber = phones.numbers.get(i).number;

                SearchResult phoneContact = new SearchResult();

                phoneContact.name = name;
                phoneContact.phone = phoneNumber;

                // 分字
                phoneContact.formatPinYin();

                String pinyinInitials = PinyinUtils.cn2FirstSpell(name, false);
                String pinyin = PinyinUtils.cn2Spell(name, false, true, true, "");

                String initialsNumber = PinyinUtils.pinyinConvertToNumber(pinyinInitials);
                String pinyinNumber = PinyinUtils.pinyinConvertToNumber(pinyin);

                // 取得名字所有字母转化为拼音
                phoneContact.pinyin = pinyin;
                // 取首字母 并 转换为 数字
                phoneContact.initials = initialsNumber;
                phoneContact.pinyinInitials = pinyinInitials;
                // 取所有字母 并 转化为 数字
                phoneContact.number = pinyinNumber;

                phoneContact.photoType = phones.photoType;
                phoneContact.photoBytes = phones.photoBytes;

                searchResults.add(phoneContact);
            
        
        return searchResults;
    

b. 建立循环, 遍历所有的已知searchResult ,    查看与检索项匹配的联系人, 添加到 result 中

    public static List<SearchResult> searchContactByAll(final List<SearchResult> source, final String query) 
        List<SearchResult> result = new ArrayList<>();
        // 汉语转拼音
        String pyInput = PinyinUtils.cn2Spell(query, false, true, true, "");
        String pyInitialInput = PinyinUtils.cn2FirstSpell(query, false);
        for (SearchResult user : source) 
            // 重置高亮
            user.resetAllHighlight();
            // 标识是否包含搜索内容
            boolean flag = false;
            // 搜索内容 不能大于 联系人拼音的长度
            // 搜索中文的时候, 我们直接遍历名字
            if (pyInput.length() <= user.pinyin.length()) 
                if(StringUtils.checkChinese(query))
                    if (user.name.contains(query)) 
                        user.priority = 1;
                        if(user.name.startsWith(query)) 
                            // 优先级为最大
                            user.priority = 0;
                        
                        //由于名字中可能含有多音字,所以使用name.indexof
                        int j = user.name.indexOf(query);
                        //避免这里出现数组越界
                        for (int i = 0; i < user.nodes.size() - j; i++) 
                            // 设置高亮
                            updateHighlight(user.nodes.get(j + i), -1);
                        
                        result.add(user);
                    
                    continue;
                

                if (StringUtils.checkChinese(user.name)) 
                    if (user.name.contains(query)) 
                        user.priority = 1;
                        if(user.name.startsWith(query)) 
                            // 优先级为最大
                            user.priority = 0;
                        

                        //由于名字中可能含有多音字,所以使用name.indexof
                        int j = user.name.indexOf(query);
                        //避免这里出现数组越界
                        for (int i = 0; i < user.nodes.size() - j; i++) 
                            // 设置高亮
                            updateHighlight(user.nodes.get(j + i), -1);
                        
                        flag = true;
                     else if (user.pinyin.toLowerCase().startsWith(pyInput.toLowerCase())) // 直接拼音匹配
                        // 优先级为1
                        user.priority = 2;
                        //避免这里出现数组越界
                        for (int i = 0; i < user.nodes.size(); i++) 
                            updateHighlight(user.nodes.get(i), -1);
                        
                        flag = true;
                     else 
                        // 深层拷贝ArrayList
                        ArrayList<PyNode> nodes = Lists.newArrayList();
                        for (PyNode pyNode : user.nodes) 
                            try 
                                PyNode node = (PyNode) pyNode.clone();
                                node.number = node.pinyin; // 注意这里换掉T9算法中的number,使用拼音代替!
                                nodes.add(node);
                             catch (CloneNotSupportedException e) 
                                e.printStackTrace();
                            
                        
                        // 全部转换为小写
                        pyInput = pyInput.toLowerCase(Locale.getDefault());
                        // 开启递归搜索
                        flag = pinyinRecursion(pyInput, 0, 1, 0, nodes, false);
                        // 优先级
                        user.priority = user.getNodeHighlightString().indexOf("1") + 400;
                    
                 else 
                    // 英文
                    String name = user.pinyin.toLowerCase(Locale.getDefault());
                    String key = query.toLowerCase(Locale.getDefault());
                    if (name.contains(key)) 
                        int length = key.length(), j = name.indexOf(key);

                        // 优先级
                        user.priority = j + 1200;

                        if(name.startsWith(key)) 
                            user.priority = j + 800;
                        

                        // 设置高亮
                        StringBuilder sb = new StringBuilder();
                        for (int i = 0; i < length; i++) 
                            sb.append(1);
                        
                        StringBuilder highlight = new StringBuilder(user.highlight[0]);
                        highlight.replace(j, length + j, sb.toString());
                        user.highlight[0] = highlight.toString();
                        flag = true;
                    
                
            
            // 搜索电话
            if (!flag && user.phone.contains(query)) 

                if(user.phone.equals(query)) 
                    user.priority = 9997;
                 else if(user.phone.startsWith(query)) 
                    user.priority = 9998;
                 else 
                    user.priority = 9999 + user.phone.indexOf(query);
                

                // 重置高亮
                user.resetAllHighlight();
                flag = true;
            
            // 判断是否匹配成功
            if (flag) 
                result.add(user);
            
        
        Collections.sort(result, new ListComparator());
        return result;
    

 

3.总结 :

主要工作就是两点, 一是把名字转化为拼音, 二是找到匹配的联系人项, 并标注匹配的字串

 

之前一直有个问题,

1. 不支持中文全拼检索 , 发现是已经检索到,只是数组越界了, 

 2. 中文会被先转为拼音,然后检索.   这个也是不对的,  正确的做法是中文检索优先级最高

 

 

 

 

以上是关于android 车机电话的通讯录联系人搜索实现解析 ------- 填坑日记的主要内容,如果未能解决你的问题,请参考以下文章

android 联系人搜索

android中拨打电话的几种实现

android手机,新建联系人在通讯录无法显示。

Android 通讯录 - 获取电话号码

Android获取手机联系人的姓名和电话

如何以编程方式修改通讯录中的联系电话?