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 车机电话的通讯录联系人搜索实现解析 ------- 填坑日记的主要内容,如果未能解决你的问题,请参考以下文章