玩爆你的手机联系人--T9搜索

    

自己研究了好几天联系人的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.显示结果出来.


各位如果觉得容易看得懂,或者自己能用到的,能不能在页面底下投一下您尊贵的一票呢,谢谢!



以上是我的思路,下面附上一段代码

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) 来隐藏键盘。 用 InputType.TYPE_NULL方法,无法显示光标。
	 */
	private void hideSystemKeyBoard(View view) {
		this.getWindow().setSoftInputMode(
				WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
		try {
			Class<EditText> cls = EditText.class;
			Method setSoftInputShownOnFocus;
			// 此方法为隐藏的需用java反射调用
			setSoftInputShownOnFocus = cls.getMethod("setShowSoftInputOnFocus",
					boolean.class);
			setSoftInputShownOnFocus.setAccessible(true);
			setSoftInputShownOnFocus.invoke((EditText) view, false);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

源码地址:(暂时被我删除了,因为好像上传错了demo,晚上回去改哈)

个人觉得以上的算法还不是最高效的,如果有更好的算法,麻烦指点指点.


尊重原创, 转载请注明出处:http://blog.csdn.net/chillax_li/article/details/29380615


posted @ 2014-06-08 20:26  w_Kong  阅读(310)  评论(0编辑  收藏  举报