• 玩爆你的手机联系人--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.显示结果出来.


    各位假设认为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) 来隐藏键盘。

    用 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


  • 相关阅读:
    商户网站使用第三方支付的大致原理和实现
    ASP.NET MVC中检测浏览器版本并提示下载更新
    如何选择使用IEnumerable, ICollection, IList
    IEnumerable和IQueryable的区别以及背后的ExpressionTree表达式树
    IEnumerable是集合,IEnumerator是集合的迭代器
    ASP.NET MVC中使用Session来保持表单的状态
    在ASP.NET MVC中实现Select多选
    总结ASP.NET MVC视图页使用jQuery传递异步数据的几种方式
    在ASP.NET MVC4中使用Quartz.NET执行定时任务
    委托, 泛型委托,Func<T>和Action<T>
  • 原文地址:https://www.cnblogs.com/ldxsuanfa/p/10921571.html
  • Copyright © 2020-2023  润新知