android 功能模块之通讯模块三分析

无情 阅读:172 2021-04-01 00:24:42 评论:0


Android通讯录开发之解决快速搜索联系人线程同步问题


2013年1月13日

上一篇博客介绍的是如何实现搜索,在PhoneUtil中已经定义好了search方法,开发者直接拿来用就ok了,但用的时候肯定会遇到线程同步问题,如何解决搜索的时候UI线程卡顿的现象,这时候就需要另开一个线程来进行搜索操作了,但由于在搜索框输入字符的时候,一般都是快速输入的,这就会导致线程同步问题的出现,搜索出来的结果会不对。小巫由于经验不足还有相关知识的欠缺,在遇到这个问题的时候一直没能解决,所以只能去请教有经验的工程师了,最终也找到解决办法。

   在UI线程我们知道超过5秒的操作就会出现卡顿或者ANR对话框,所以一般费时的操作绝不能放在UI线程,但数据的更新和通知就要放在UI线程来实现了,比如ListView的adapter的数据更新就要在UI线程里通知,不然就可能出现数据没有得到即使更新的现象。

   这些问题只有在实际开发当中才会遇到,我废话也不多说了,下面是解决方案。

   搜索框,文本变化的监听

  

  1. searchEditText.addTextChangedListener(new TextWatcher() {  
  2.   
  3.             @Override  
  4.             public void onTextChanged(final CharSequence s, int start,  
  5.                     int before, int count) {  
  6.                 if (!TextUtils.isEmpty(s)) {  
  7.                     btnClear.setVisibility(View.VISIBLE);  
  8.                     selectAllBtn.setVisibility(View.GONE);  
  9.                     searchList(s.toString());  
  10.                 } else { // 如果输入框内容为空,显示全部  
  11.                     btnClear.setVisibility(View.GONE);  
  12.                     selectAllBtn.setVisibility(View.VISIBLE);  
  13.                     searchList("");  
  14.                 }  
  15.             }  
  16.   
  17.             @Override  
  18.             public void beforeTextChanged(CharSequence s, int start, int count,  
  19.                     int after) {  
  20.             }  
  21.   
  22.             @Override  
  23.             public void afterTextChanged(final Editable s) {  
  24.   
  25.             }  
  26.   
  27.         });  
searchEditText.addTextChangedListener(new TextWatcher() { 
 
			@Override 
			public void onTextChanged(final CharSequence s, int start, 
					int before, int count) { 
				if (!TextUtils.isEmpty(s)) { 
					btnClear.setVisibility(View.VISIBLE); 
					selectAllBtn.setVisibility(View.GONE); 
					searchList(s.toString()); 
				} else {// 如果输入框内容为空,显示全部 
					btnClear.setVisibility(View.GONE); 
					selectAllBtn.setVisibility(View.VISIBLE); 
					searchList(""); 
				} 
			} 
 
			@Override 
			public void beforeTextChanged(CharSequence s, int start, int count, 
					int after) { 
			} 
 
			@Override 
			public void afterTextChanged(final Editable s) { 
 
			} 
 
		}); 

一般搜索框会有删除的×,我这里还有控制显示全选的框,效果如下:





在文本变化的时候会不断刷新列表,会调用searchList的方法,通过传递字符串来实现更新列表

通过lastest这个标识来解决线程同步问题,只有i跟lastest相等的时候采取刷新列表,其实这个办法并不土,不知道网友是否有更好的实现方法,麻烦指教一下。

  1. private static int lastest = 0;  
  2.   
  3. // 实现线程同步搜索联系人  
  4. // 线程同步问题可能会导致数据显示错误,比如会显示上一次搜索到的数据  
  5. public void searchList(final String s) {  
  6.     // 用户可能正在快速输入电话号码,之前在搜索的联系人列表已经过时了。  
  7.     final int i = ++lastest;  
  8.     // 开一个线程来进行快速搜索  
  9.     new Thread(new Runnable() {  
  10.   
  11.         @Override  
  12.         public void run() {  
  13.             if (TextUtils.isEmpty(s)) {  
  14.                 // 如果输入的字符串为空,则显示所有联系人  
  15.                 searchContacts = allContacts;  
  16.             } else {  
  17.                 // searhContacts指向搜索返回的list  
  18.                 searchContacts = PhoneUtil.search(s, allContacts);  
  19.             }  
  20.   
  21.             if (i == lastest) { // 避免线程同步问题  
  22.                 LocalContactActivity.this.runOnUiThread(new Runnable() {  
  23.   
  24.                     @Override  
  25.                     public void run() {  
  26.                         if (i == lastest) { // 避免线程同步问题  
  27.                             contactList.clear();  
  28.                             contactList.addAll(searchContacts);  
  29.                             refreshList();  
  30.                         }  
  31.                     }  
  32.                 });  
  33.             }  
  34.         }  
  35.     }).start();  
  36. }  
	private static int lastest = 0; 
 
	// 实现线程同步搜索联系人 
	// 线程同步问题可能会导致数据显示错误,比如会显示上一次搜索到的数据 
	public void searchList(final String s) { 
		// 用户可能正在快速输入电话号码,之前在搜索的联系人列表已经过时了。 
		final int i = ++lastest; 
		// 开一个线程来进行快速搜索 
		new Thread(new Runnable() { 
 
			@Override 
			public void run() { 
				if (TextUtils.isEmpty(s)) { 
					// 如果输入的字符串为空,则显示所有联系人 
					searchContacts = allContacts; 
				} else { 
					// searhContacts指向搜索返回的list 
					searchContacts = PhoneUtil.search(s, allContacts); 
				} 
 
				if (i == lastest) { // 避免线程同步问题 
					LocalContactActivity.this.runOnUiThread(new Runnable() { 
 
						@Override 
						public void run() { 
							if (i == lastest) { // 避免线程同步问题 
								contactList.clear(); 
								contactList.addAll(searchContacts); 
								refreshList(); 
							} 
						} 
					}); 
				} 
			} 
		}).start(); 
	}

数据有更新,调用adapter的notifyDataSetChanged()方法就可以达到刷新列表效果。


  1. /** 刷新列表和确认按钮 **/  
  2. public void refreshList() {  
  3.     // adapter.setContactList(contactList);  
  4.     adapter.notifyDataSetChanged();  
  5.     refreshBtnOK();  
  6.   
  7. }  
	/** 刷新列表和确认按钮 **/ 
	public void refreshList() { 
		// adapter.setContactList(contactList); 
		adapter.notifyDataSetChanged(); 
		refreshBtnOK(); 
 
	}


不知道以上解决方案有没有帮你解决问题,如果没有麻烦请告知一声。

下篇博客会介绍如何实现全选、反选、删除等功能,敬请期待。

声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

发表评论
搜索
排行榜
关注我们

一个IT知识分享的公众号