android 车机电话的通讯录联系人搜索实现解析 ------- 填坑日记
16lz
2021-01-24
项目中的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 phoneNumTypeList = new ArrayList<>(); private List phoneNumList = new ArrayList<>(); public List numbers = new ArrayList<>(); private List 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 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 convertFormatSearchResult(List contactsList) { Lg.i(TAG, " convertFormatSearchResult "); if (contactsList == null || contactsList.isEmpty()) { return Lists.newArrayList(); } List 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 searchContactByAll(final List source, final String query) { List 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 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. 中文会被先转为拼音,然后检索. 这个也是不对的, 正确的做法是中文检索优先级最高
更多相关文章
- 同样line-height下ios和Android显示不一致的问题
- android/NDK开发assets资源中文名打包问题
- Linux Kernel and Android(安卓)休眠与唤醒(中文版)
- android JNI C代码对sdcard中文件的操作
- Android(安卓)权限中文说明
- RxJava RxAndroid(安卓)资源收录
- Android(安卓)Studio 3.1.2 新项目报错 AAPT2 error: check logs
- Android(安卓)Studio 2.0 正式版发布啦 (首次中文翻译)
- Android(安卓)四大组件之一 :BroadCastReceiver 广播接收器详解