自己研究了好几天联系人的T9搜索算法, 先分享出来给大家看看. 欢迎不吝赐教.假设有大神有更好的T9搜索算法, 那更好啊,大家一起研究研究,谢谢.
第一部分是比較简单的获取手机联系人.
获取联系人前提要有权限.
<uses-permission android:name="android.permission.READ_CONTACTS" />
由于手机的联系人都存储在数据库里面,所以我们仅仅要把数据库里的信息查询出来就可以.
private static final String[] PHONES_PROJECTION = new String[] {
Phone.DISPLAY_NAME, Phone.NUMBER, Photo.SORT_KEY_ALTERNATIVE};
ContentResolver resolver = getBaseContext().getContentResolver();
Cursor phoneCursor = resolver.query(Phone.CONTENT_URI,
PHONES_PROJECTION, null, null, null);
这里我仅仅是简单的说一下而已,后面的遍历phoneCursor 就能把联系人查询出来.(我项目里是开一条线程获取联系人的,以防太多联系人导致页面空白或者卡顿)
第二部分是T9搜索部分
思路是: a仅仅要联系人的号码有包括我输入的数字就add到list进去,
b联系人的姓名拼音有包括我输入的拼音就add到list进去,
c联系人的姓名缩写拼音有包括我输入的拼音就add到list进去
举个样例--联系人姓名:測试,号码:1234567890
情况一:我输入1234567890就能把測试显示出来
情况二:我输入23744(ceshi),由于这个"測试"的拼音,所以也能把測试显示出来
情况三:我输入(27)cs,这是"測试"的拼音缩写,所以也能把測试显示出来
当然我输入23(ce)或者744(shi)什么的,都能够把測试显示出来.
个人是把联系人的号码(1234567890),姓名拼音转成数字(ceshi相应是23744),拼音缩写拼音转成数字(cs相应27),这些信息存储到list里面.便于遍历跟比較.
然后再结合代码解说一下:
我的流程是这种:
首先開始发送一条线程去获取联系人
/**
* 刚開始启动程序时,开条线程去获取联系人
*/
new Thread(getContract).start();
这线程里面获取到的联系人存储到mLIst里面;
当中在获取的时候处理了一下,把联系人姓名,号码,拼音,拼音缩写查出来后放到bean里面;
private static final String[] PHONES_PROJECTION = new String[] {
Phone.DISPLAY_NAME, Phone.NUMBER, Photo.SORT_KEY_ALTERNATIVE};
这个是查出联系人的姓名,号码,姓名拼音:測试,1234567890,CE 測 SHI 试
(对Contacts了解就会知道(不了解能够了解下),每一个联系人都有一个sort_key字段,假设查询中没有设置sortOrder,默认就会以 sort_key字段为排序依据.名字的检索事实上也是依据sort_key来做的(比方拨号盘的模糊匹配:数字转成字母。再到拼音,最后得到汉字).sort_key是依据名字生成的:假设联系人名字中包括字母。sort_key和name保持一致;假设名字是汉字,生成的sort_key,"拼音 汉字-拼音 汉字".当中拼音全大写,中间以空格切割,如:"測试"相应的sort_key:"CE
測 SHI 试")
外语:格式就是以上那样,由于Google有提供一个汉字转拼音的类,然后把"CE 測 SHI 试"存储到数据库里.所以用这个就能查出来.但毕竟是外国人弄的,所以在拼音上有时候会有一些差池.比如咱们常见的"呵呵",咱们习惯是"HE 呵 HE 呵",但它可能会保存成"A 呵 A 呵".
/**
* 将联系人的姓名拼音所有转化为数字
* @param 联系人姓名拼音
* @return 姓名拼音相应数字
*/
public String getNum(String search, boolean status){
String str = "";
for(int i = 0;i<search.length();i++){
String c = search.charAt(i)+"";
if(c.equals("1")){
str = str + "1";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("A")||c.equals("B")||c.equals("C")||c.equals("2")
||c.equals("a")||c.equals("b")||c.equals("c")){
str = str + "2";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("D")||c.equals("E")||c.equals("F")||c.equals("3")
||c.equals("d")||c.equals("e")||c.equals("f")){
str = str + "3";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("G")||c.equals("H")||c.equals("I")||c.equals("4")
||c.equals("g")||c.equals("h")||c.equals("i")){
str = str + "4";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("J")||c.equals("K")||c.equals("L")||c.equals("5")
||c.equals("j")||c.equals("k")||c.equals("l")){
str = str + "5";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("M")||c.equals("N")||c.equals("O")||c.equals("6")
||c.equals("m")||c.equals("n")||c.equals("o")){
str = str + "6";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("P")||c.equals("Q")||c.equals("R")||c.equals("S")||c.equals("7")
||c.equals("p")||c.equals("q")||c.equals("r")||c.equals("s")){
str = str + "7";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("T")||c.equals("U")||c.equals("V")||c.equals("8")
||c.equals("t")||c.equals("u")||c.equals("v")){
str = str + "8";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("W")||c.equals("X")||c.equals("Y")||c.equals("Z")||c.equals("9")
||c.equals("w")||c.equals("x")||c.equals("y")||c.equals("z")){
str = str + "9";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("0")){
str = str + "0";
if(status){
i = i + 1;
}
continue;
}
}
return str;
};
这种方法主要是将拼音转换成数字,比如測试的"ce 測 shi 试"就能转成23744.大家预计还看到我还传了个參数boolean status,这个是用于判读是否为拼音字母缩写的,假设为true的话,他会查出測试的"ce
測 shi 试"的字母缩写,cs转成27.
获取到联系人,再显示出来之后,就是搜索了.
整个的事件监听关键在于edittext的变化监听
inputEditText.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
if (isWrite) {
isWrite = false;
return;
}
isWrite = true;
String inputStr = "";
String newStr = s.toString();
newStr = newStr.replace(" ", "");
int index = 0;
if (true) {
if ((index + 3) < newStr.length()) {
inputStr += (newStr.substring(index, index + 3) + " ");
index += 3;
}
}
while ((index + 4) < newStr.length()) {
inputStr += (newStr.substring(index, index + 4) + " ");
index += 4;
}
inputStr += (newStr.substring(index, newStr.length()));
inputEditText.setText(inputStr);
inputEditText.setSelection(inputStr.length());
if(count == 0){
isAfresh = true;
}else{
isAfresh = false;
}
long currentTime = System.currentTimeMillis();
if ((currentTime - touchTime) >= waitTime) {
touchTime = currentTime;
searchConstract(isAfresh);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
前面一段是为了格式化输入格式.后面调用的方法才是做相应的操作.直接依据用户输入的数字,推断联系人的姓名拼音,姓名缩写,号码有没有包括用户输入的数字,有的话就add到list里面.遍历完整个联系人之后,就刷新adapter.显示结果出来.
各位假设认为easy看得懂,或者自己能用到的,能不能在页面底下投一下您尊贵的一票呢,谢谢!
以上是我的思路,以下附上一段代码
public class MainT9 extends Activity{
private int[] textViewId = new int[]{R.id.main_num_1,R.id.main_num_2,R.id.main_num_3,R.id.main_num_4,
R.id.main_num_5,R.id.main_num_6,R.id.main_num_7,R.id.main_num_8,R.id.main_num_9,R.id.main_num_left,
R.id.main_num_0,R.id.main_num_right,R.id.main_num_delete};
private TextView[] textView = new TextView[textViewId.length];
private EditText inputEditText;
private ListView mListView;
private List<ContractBean> mList;
private List<ContractBean> list;
private MyAdapter myAdapter;
private static final String[] PHONES_PROJECTION = new String[] {
Phone.DISPLAY_NAME, Phone.NUMBER, Photo.SORT_KEY_ALTERNATIVE};
long waitTime = 300;
long touchTime = 0;
/**
* 推断是否人为输入
*/
private boolean isWrite = false;
private boolean isAfresh = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main_activity);
mList = new ArrayList<ContractBean>();
list = new ArrayList<ContractBean>();
/**
* 刚開始启动程序时,开条线程去获取联系人
*/
new Thread(getContract).start();
for(int i = 0;i<textViewId.length;i++){
textView[i] = (TextView) this.findViewById(textViewId[i]);
textView[i].setOnClickListener(click);
}
inputEditText = (EditText) this.findViewById(R.id.main_num_edit);
// hideSystemKeyBoard(inputEditText);
mListView = (ListView) this.findViewById(R.id.main_contract_listview);
myAdapter = new MyAdapter(this, mList);
mListView.setAdapter(myAdapter);
inputEditText.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// TODO Auto-generated method stub
if (isWrite) {
isWrite = false;
return;
}
isWrite = true;
String inputStr = "";
String newStr = s.toString();
newStr = newStr.replace(" ", "");
int index = 0;
if (true) {
if ((index + 3) < newStr.length()) {
inputStr += (newStr.substring(index, index + 3) + " ");
index += 3;
}
}
while ((index + 4) < newStr.length()) {
inputStr += (newStr.substring(index, index + 4) + " ");
index += 4;
}
inputStr += (newStr.substring(index, newStr.length()));
inputEditText.setText(inputStr);
inputEditText.setSelection(inputStr.length());
if(count == 0){
isAfresh = true;
}else{
isAfresh = false;
}
long currentTime = System.currentTimeMillis();
if ((currentTime - touchTime) >= waitTime) {
touchTime = currentTime;
searchConstract(isAfresh);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// TODO Auto-generated method stub
}
@Override
public void afterTextChanged(Editable s) {
// TODO Auto-generated method stub
}
});
}
private void searchConstract(boolean isAfresh){
if(isAfresh){
if(mList!=null){
myAdapter.updateListView(mList);
}else{
new Thread(getContract).start();
}
}else{
String str1= inputEditText.getText().toString();
str1 = str1.replace(" ", "");
SearchContract search = new SearchContract(str1);
search.start();
}
}
/**
* T9搜索线程
* @author Chillax_KUN
*/
class SearchContract extends Thread{
String body;
SearchContract(String body){
this.body = body;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
Iterator<ContractBean> iterator = mList.iterator();
list = new ArrayList<ContractBean>();
list.clear();
while(iterator.hasNext()){
ContractBean sortModel = iterator.next();
String search = sortModel.getSearch();
String phone = sortModel.getPhone();
phone = phone.replace(" ", "");
String zimu = sortModel.getZimu();
if(phone.contains(body) || search.contains(body)||zimu.contains(body)){
list.add(sortModel);
}
}
h.sendEmptyMessage(1);
}
}
/**
* 开启线程,获取联系人
*/
Runnable getContract = new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
mList = getPhoneContacts();
h.sendEmptyMessage(0);
}
};
private List<ContractBean> getPhoneContacts() {
ContentResolver resolver = getBaseContext().getContentResolver();
Cursor phoneCursor = resolver.query(Phone.CONTENT_URI,
PHONES_PROJECTION, null, null, null);
List<ContractBean> mList = new ArrayList<ContractBean>();
if (phoneCursor != null) {
phoneCursor.moveToFirst();
while (!phoneCursor.isAfterLast()) {
ContractBean model = new ContractBean();
String name = phoneCursor.getString(0);
String phone = phoneCursor.getString(1);
String search = phoneCursor.getString(2);
model.setName(name);
model.setPhone(phone);
model.setSearch(getNum(search,false));
String zimu = "";
String str[] = search.split(" ");
if(str.length>0){
for(int i = 0;i<str.length;i++){
if(str[i].length()==1){
zimu = zimu + str[i];
}
}
}
model.setZimu(getNum(zimu,true));
mList.add(model);
phoneCursor.moveToNext();
}
if(phoneCursor!=null){
phoneCursor.close();
}
return mList;
}
return mList;
}
/**
* 将联系人的姓名拼音所有转化为数字
* @param 联系人姓名拼音
* @return 姓名拼音相应数字
*/
public String getNum(String search, boolean status){
String str = "";
for(int i = 0;i<search.length();i++){
String c = search.charAt(i)+"";
if(c.equals("1")){
str = str + "1";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("A")||c.equals("B")||c.equals("C")||c.equals("2")
||c.equals("a")||c.equals("b")||c.equals("c")){
str = str + "2";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("D")||c.equals("E")||c.equals("F")||c.equals("3")
||c.equals("d")||c.equals("e")||c.equals("f")){
str = str + "3";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("G")||c.equals("H")||c.equals("I")||c.equals("4")
||c.equals("g")||c.equals("h")||c.equals("i")){
str = str + "4";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("J")||c.equals("K")||c.equals("L")||c.equals("5")
||c.equals("j")||c.equals("k")||c.equals("l")){
str = str + "5";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("M")||c.equals("N")||c.equals("O")||c.equals("6")
||c.equals("m")||c.equals("n")||c.equals("o")){
str = str + "6";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("P")||c.equals("Q")||c.equals("R")||c.equals("S")||c.equals("7")
||c.equals("p")||c.equals("q")||c.equals("r")||c.equals("s")){
str = str + "7";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("T")||c.equals("U")||c.equals("V")||c.equals("8")
||c.equals("t")||c.equals("u")||c.equals("v")){
str = str + "8";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("W")||c.equals("X")||c.equals("Y")||c.equals("Z")||c.equals("9")
||c.equals("w")||c.equals("x")||c.equals("y")||c.equals("z")){
str = str + "9";
if(status){
i = i + 1;
}
continue;
}else if(c.equals("0")){
str = str + "0";
if(status){
i = i + 1;
}
continue;
}
}
return str;
};
Handler h = new Handler(){
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
if(msg.what==0){
if(mList!=null && myAdapter!=null){
myAdapter.updateListView(mList);
myAdapter.notifyDataSetChanged();
}
} else if(msg.what==1){
myAdapter.updateListView(list);
}
}
};
OnClickListener click = new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.main_num_1:
inputEditText.setText(inputEditText.getText()+"1");
inputEditText.setSelection(inputEditText.getText().toString().length());
break;
case R.id.main_num_2:
inputEditText.setText(inputEditText.getText()+"2");
inputEditText.setSelection(inputEditText.getText().toString().length());
break;
case R.id.main_num_3:
inputEditText.setText(inputEditText.getText()+"3");
inputEditText.setSelection(inputEditText.getText().toString().length());
break;
case R.id.main_num_4:
inputEditText.setText(inputEditText.getText()+"4");
inputEditText.setSelection(inputEditText.getText().toString().length());
break;
case R.id.main_num_5:
inputEditText.setText(inputEditText.getText()+"5");
inputEditText.setSelection(inputEditText.getText().toString().length());
break;
case R.id.main_num_6:
inputEditText.setText(inputEditText.getText()+"6");
inputEditText.setSelection(inputEditText.getText().toString().length());
break;
case R.id.main_num_7:
inputEditText.setText(inputEditText.getText()+"7");
inputEditText.setSelection(inputEditText.getText().toString().length());
break;
case R.id.main_num_8:
inputEditText.setText(inputEditText.getText()+"8");
inputEditText.setSelection(inputEditText.getText().toString().length());
break;
case R.id.main_num_9:
inputEditText.setText(inputEditText.getText()+"9");
inputEditText.setSelection(inputEditText.getText().toString().length());
break;
case R.id.main_num_0:
inputEditText.setText(inputEditText.getText()+"0");
inputEditText.setSelection(inputEditText.getText().toString().length());
break;
case R.id.main_num_left:
inputEditText.setText(inputEditText.getText()+"*");
inputEditText.setSelection(inputEditText.getText().toString().length());
break;
case R.id.main_num_right:
inputEditText.setText(inputEditText.getText()+"#");
inputEditText.setSelection(inputEditText.getText().toString().length());
break;
case R.id.main_num_delete:
String string = inputEditText.getText().toString();
if(!string.equals("")){
inputEditText.setText(string.subSequence(0, string.length()-1));
inputEditText.setSelection(inputEditText.getText().toString().length());
}
break;
default:
break;
}
}
};
/**
* 通过反射调用setShowSoftInputOnFocus(false) 来隐藏键盘。