基于Android的短信应用开发(九)——AsyncQueryHandler异步读取会话信息

在前面的文章:基于Android的短信应用开发(五)中,我们通过ContentResolver读取了手机短信会话列表,但是,通过ContentResolver直接从数据库读取的方式是存在问题的,之前的做法是实际上是直接在UI线程中进行数据库读取操作,在读取少量数据记录的情况下可能还影响不大,但是在需要操作的数据量较大,如有几百成千个短信会话时,数据的读取是需要花费一定时间的。而直接在UI线程中执行耗时操作将会阻塞线程,阻塞超过一定时间时(一般是5s)时将会造成ANR(程序无响应)的后果。为了避免出现这种情况,我们可以使用AsyncQueryHandler来异步地执行耗时的数据查询操作,下面就来看一下如何通过AsyncQueryHandler来改进之前读取会话信息的操作。

我们先来看一下之前是如何读取会话记录的,具体实现为MessageListAdapter.java的getMessageSessions()方法,下面是其源码:

public void getMessageSessions(){  
    	Cursor sessionCursor = null;
    	ContentResolver resolver = null; 
    	ContactData contact = null;
    	
    	try{
           	Uri uri = Uri.parse(SMS_URI_ALL);
	    	resolver = mContext.getContentResolver();
	    	sessionCursor = resolver.query(uri, new String[]  
	        { "* from threads--" }, null, null, null);  
	    	
	    	if (sessionCursor == null) {
				return;
			}	
			if (sessionCursor.getCount() == 0){
				sessionCursor.close();
				sessionCursor = null;
				return;
			}
	          
			sessionCursor.moveToFirst();
	        while (sessionCursor.isAfterLast() == false)  
	        {  
	        	/*
	        	threads表各字段含义如下:
	        	1._id为会话id,他关联到sms表中的thread_id字段。
	        	2.recipient_ids为联系人ID,这个ID不是联系人表中的_id,而是指向表canonical_address里的id,
	        	canonical_address这个表同样位于mmssms.db,它映射了recipient_ids到一个电话号码,也就是说,
	        	最终获取联系人信息,还是得通过电话号码;
	        	3.mesage_count该会话的消息数量
	        	4.snippet为最后收到或发出的信息	        	
	        	*/
	        	
	            int thread_idColumn = sessionCursor.getColumnIndex("_id");  
	            int dateColumn = sessionCursor.getColumnIndex("date");  
	            int message_countColumn = sessionCursor.getColumnIndex("message_count");  
	            int snippetColumn = sessionCursor.getColumnIndex("snippet");  
	            int typeColumn = sessionCursor.getColumnIndex("type");
	                          
	            //格式化短信日期显示   
	            Date date = new Date(Long.parseLong(sessionCursor.getString(dateColumn)));    
	              
	            //获得短信的各项内容  
	            //phoneAndUnread[0]存放电话号码,phoneAndUnread[1]存放该会话中未读信息数
	            String threadId = sessionCursor.getString(thread_idColumn);
	            String phoneAndUnread[]=getPhoneNum(threadId);  
	            String phone = phoneAndUnread[0];
	            String unreadCount = phoneAndUnread[1];
	            String last_mms=sessionCursor.getString(snippetColumn);   
	            String date_mms=date.toString();  
	            String count_mms=sessionCursor.getString(message_countColumn);  
	            String type = sessionCursor.getString(typeColumn);
	            
	            SMSInfo smsinfo = new SMSInfo();
	            
	            /*  
	            phoneAndUnread[0]存放电话号码 
	            */ 
	            contact = getContactFromPhoneNum(mContext, phoneAndUnread[0]); 
	              
	            //获得会话的未读短信与所有短信数  
	            String final_count=unreadCount+"/"+count_mms;  	        
	            
	            smsinfo.setContactNumber(phone);
	            smsinfo.setContactName(contact.getContactName());
	            
	            //如果有该信息会话人头像,则设置已有头像,如果没有则给他设置一个默认的头像
	            if (contact.getPhotoUri() == null){ 
	            	smsinfo.setContactPhoto(BitmapFactory.decodeResource(
		        			mContext.getResources(), R.drawable.ic_launcher));	            		            
	           }else{  
	            	Uri photoUri = contact.getPhotoUri();
	            	InputStream input = ContactsContract.Contacts.
		            		openContactPhotoInputStream(resolver, photoUri);  
	            	smsinfo.setContactPhoto(BitmapFactory.decodeStream(input)); 
	            }	            
	            
	            smsinfo.setDate(date_mms);
	            smsinfo.setSmsbody(last_mms);
	            smsinfo.setType(type);
	            smsinfo.setMessageCout(final_count);
	            smsinfo.setThreadId(threadId);
	            infos.add(smsinfo);
	            sessionCursor.moveToNext();
	        } 
	        	sessionCursor.close();
    	}catch(Exception e){
    		Log.e(ThreadTAG,"E:" + e.toString());
    	}finally{
			if (sessionCursor != null){
				sessionCursor.close();
				sessionCursor = null;
			}
	}
  
}  
可以看到,上面的方法是通过ContentResolver的query()执行查询的,而当使用AsyncQueryHandler进行异步查询时,又应该怎样做呢?我们需要做两件事,1.自定义Handler类并 继承AsyncQueryHandler,实现其构造方法(可直接使用父类AsyncQueryHandler的构造方法)以及onQueryComplete()方法;2.直接调用1中定义的Handler的startQuery()方法,下面来看一下具体的做法。

1.定义MessageListQueryHandler类继承自AsyncQueryHandler

public class MessageListQueryHandler extends AsyncQueryHandler{

		public MessageListQueryHandler(ContentResolver cr) {
			super(cr);
			// TODO Auto-generated constructor stub
		}

		@Override
		protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
			// TODO Auto-generated method stub
			super.onQueryComplete(token, cookie, cursor);
	    	ContactData contact = null;
	    	ContentResolver resolver = mContext.getContentResolver();
	    	
	    	if (cursor == null) {
				return;
			}	
			if (cursor.getCount() == 0){
				cursor.close();
				cursor = null;
				return;
			}
			
			cursor.moveToFirst();
	        while (cursor.isAfterLast() == false)  
	        {  
	        	/*
	        	threads表各字段含义如下:
	        	1._id为会话id,他关联到sms表中的thread_id字段。
	        	2.recipient_ids为联系人ID,这个ID不是联系人表中的_id,而是指向表canonical_address里的id,
	        	canonical_address这个表同样位于mmssms.db,它映射了recipient_ids到一个电话号码,也就是说,
	        	最终获取联系人信息,还是得通过电话号码;
	        	3.mesage_count该会话的消息数量
	        	4.snippet为最后收到或发出的信息	        	
	        	*/
	        	
	            int thread_idColumn = cursor.getColumnIndex("_id");  
	            int dateColumn = cursor.getColumnIndex("date");  
	            int message_countColumn = cursor.getColumnIndex("message_count");  
	            int snippetColumn = cursor.getColumnIndex("snippet");  
	            int typeColumn = cursor.getColumnIndex("type");
	                          
	            //格式化短信日期显示   
	            Date date = new Date(Long.parseLong(cursor.getString(dateColumn)));    
	              
	            //获得短信的各项内容  
	            //phoneAndUnread[0]存放电话号码,phoneAndUnread[1]存放该会话中未读信息数
	            String threadId = cursor.getString(thread_idColumn);
	            String phoneAndUnread[]=getPhoneNum(threadId);  
	            String phone = phoneAndUnread[0];
	            String unreadCount = phoneAndUnread[1];
	            String last_mms=cursor.getString(snippetColumn);   
	            String date_mms=date.toString();  
	            String count_mms=cursor.getString(message_countColumn);  
	            String type = cursor.getString(typeColumn);
	            
	            SMSInfo smsinfo = new SMSInfo();
	            
	            /*  
	            phoneAndUnread[0]存放电话号码 
	            */ 
	            contact = getContactFromPhoneNum(mContext, phoneAndUnread[0]); 
	              
	            //获得会话的未读短信与所有短信数  
	            String final_count=unreadCount+"/"+count_mms;  	        
	            
	            smsinfo.setContactNumber(phone);
	            smsinfo.setContactName(contact.getContactName());
	            
	            //如果有该信息会话人头像,则设置已有头像,如果没有则给他设置一个默认的头像
	            if (contact.getPhotoUri() == null){ 
	            	smsinfo.setContactPhoto(BitmapFactory.decodeResource(
		        			mContext.getResources(), R.drawable.ic_launcher));	            		            
	           }else{  
	            	Uri photoUri = contact.getPhotoUri();
	            	InputStream input = ContactsContract.Contacts.
		            		openContactPhotoInputStream(resolver, photoUri);  
	            	smsinfo.setContactPhoto(BitmapFactory.decodeStream(input)); 
	            }	            
	            
	            smsinfo.setDate(date_mms);
	            smsinfo.setSmsbody(last_mms);
	            smsinfo.setType(type);
	            smsinfo.setMessageCout(final_count);
	            smsinfo.setThreadId(threadId);
	            infos.add(smsinfo);
	            cursor.moveToNext();
	        } 
	        	cursor.close();
		}		
}	
在其构造方法中,直接调用父类AsyncQueryHandler的构造方法即可,重头戏是onQueryComplete()方法,此方法将在异步查询完成后,根据数据库查询的结果进行后续的处理操作,在此处基本上是将之前getMessageSessions()中的操作移到了 onQueryComplete()中执行,同时将getMessageSessions()中原有获取查询结果后的操作去掉。
2.在 getMessageSessions()中调用 MessageListQueryHandler的startQuery()方法

在上一步中,我们已经将获取数据库查询结果后的相关操作移到了MessageListQueryHandler的onQueryComplete()中去了,因此,在此时的getMessageSessions()中,我们只需调用MessageListQueryHandler的startQuery()方法就可以了,startQuery()定义如下:

  void     startQuery(int token,  Object cookie,  Uri uri,  String[] projection,  String selection,  String[] selectionArgs,  String orderBy)  
  This method begins an asynchronous query.

参数解释:

token,一个令牌,主要用来标识查询,保证唯一即可.需要跟onQueryComplete方法传入的一致。(当然你也可以不一致,同样在数据库的操作结束后会调用对应的onQueryComplete方法 );

cookie,你想传给onXXXComplete方法使用的一个对象。(没有的话传递null即可)

其他的五个参数与ContentResolver的query()方法参数相对应,即:

Uri uri 进行查询的通用资源标志符:

projection 查询的列 

selection  限制条件 

selectionArgs 查询参数

orderBy 排序条件

OK,方法解释完了,我们还是来看一下 getMessageSessions()新的定义吧。

 public void getMessageSessions(){ 
    	Uri uri = Uri.parse(SMS_URI_ALL);   
        String[] projection = new String[] { "* from threads--" };    
        messageListQueryHandler = new MessageListQueryHandler(mContext.getContentResolver());
        messageListQueryHandler.startQuery(0, null, uri, projection, null, null,null); 
    }
好了,通过上面的两步走,我们就已经成功将数据查询的工作从UI线程转移到AsyncQueryHandler中去了,过程也并不复杂,只需要将数据处理操作放到 AsyncQueryHandler的 onQueryComplete()方法中去,然后调用AsyncQueryHandler的startQuery()就可以搞定啦。

参考文章链接:http://blog.csdn.net/honeybaby201314/article/details/42492251

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值