最近在做一个项目,要求:导出每个号码最新的短信记录,要求显示人名,号码,最近的一条短信内容且以时间降序排列。
短信数据库存储路径:“./data/data/com.android.providers.telephony/databases/mmssms.db”
短信、彩信的数据库的结构和模型讲解见:http://www.cnblogs.com/shaweng/archive/2012/05/26/2518949.html
目前的方法有五种:
方法一:
SQL语句为:select date, body, address, type from sms where (length(address)>0) group by (thread_id) order by date desc
但是不能够导出草稿记录
void getSmsData(Context cnt) { ContentResolver resolver = cnt.getContentResolver(); Cursor cursor = null; try { cursor = resolver.query(Sms.CONTENT_URI, new String[] { Telephony.Sms.DATE, Telephony.Sms.BODY, Telephony.Sms.ADDRESS, Telephony.Sms.TYPE }, "length(" + Telephony.Sms.ADDRESS + ")>0) group by (" + Telephony.Sms.THREAD_ID, null, Telephony.Sms.DEFAULT_SORT_ORDER); // 提高cursor访问速度 if (cursor != null) { int count = cursor.getCount(); cursor.moveToFirst(); synchronized (mImportDataList) {//正序查找 for (int i = 0; i < count; i++) { cursor.moveToPosition(i); long smsDate = cursor.getLong(0);//设置最新一条短信的时间 String smsBody = cursor.getString(1); // 內容 String phoneNum = cursor.getString(2); // 电话号码 int smsType = cursor.getInt(3); // 短信类型 Log.i("DEBUG", "smsDate = " + smsDate + ",smsBody=" + smsBody + ",phoneNum=" + phoneNum + ",smsType=" + smsType); } } cursor.close(); } } catch (Exception e) { Log.w(TAG, e.toString()); cursor = null; } finally { if (cursor != null) { cursor.close(); } } }
方法二:
SQL 语句:
select a.date,a.snippet,b.address,b.type from threads a, sms b where a._id = b.thread_id group by b.address order by a.date desc --from sms
多表查询,同时查询表threads和sms。即先查出thread_ID,然后取出该thread_ID对应的电话号码和内容等
参考网址:http://bbs.csdn.net/topics/340237133
但是也不能够导出草稿记录
void getSmsData(Context cnt) { ContentResolver resolver = cnt.getContentResolver(); Cursor cursor = null; try { cursor = resolver.query(Sms.CONTENT_URI,new String[] { " a.date,a.snippet", " b.address,b.type from threads a", " sms b where a._id = b.thread_id group by b.address order by a.date desc-- ", }, null, null, null); // 提高cursor访问速度 if (cursor != null) { int count = cursor.getCount(); cursor.moveToFirst(); synchronized (mImportDataList) {//正序查找 for (int i = 0; i < count; i++) { cursor.moveToPosition(i); long smsDate = cursor.getLong(0);//设置最新一条短信的时间 String smsBody = cursor.getString(1); // 內容 String phoneNum = cursor.getString(2); // 电话号码 int smsType = cursor.getInt(3); // 短信类型 Log.i("DEBUG", "smsDate = " + smsDate + ", smsBody=" + smsBody + ",phoneNum=" + phoneNum + ",smsType=" + smsType); } } cursor.close(); } } catch (Exception e) { Log.w(TAG, e.toString()); cursor = null; } finally { if (cursor != null) { cursor.close(); } } }
方法三:
SQL 语句:
select a.date,a.snippet,b.address,b.type from threads a, sms b where a._id = b.thread_id group by a.date --from sms
它是方法二的变种,能够转换为android方式的查询数据库。
注意该方式的弊端是,无法满足不同号码的短信的时间相同时,会漏掉短信。因为它是以日期为group by。实现方式如下:
void getSmsData(Context cnt) { ContentResolver resolver = cnt.getContentResolver(); Cursor cursor = null; try { cursor = resolver.query(Sms.CONTENT_URI,new String[] { " a.date,a.snippet", " b.address,b.type from threads a", " sms b where a._id = b.thread_id group by b.date-- ", }, null, null, null); // 提高cursor访问速度 if (cursor != null) { int count = cursor.getCount(); cursor.moveToFirst(); synchronized (mImportDataList) {//正序查找 for (int i = 0; i < count; i++) { cursor.moveToPosition(i); long smsDate = cursor.getLong(0);//设置最新一条短信的时间 String smsBody = cursor.getString(1); // 內容 String phoneNum = cursor.getString(2); // 电话号码 int smsType = cursor.getInt(3); // 短信类型 Log.i("DEBUG", "smsDate = " + smsDate + ",smsBody=" + smsBody + ",phoneNum=" + phoneNum + ",smsType=" + smsType); } } cursor.close(); } } catch (Exception e) { Log.w(TAG, e.toString()); cursor = null; } finally { if (cursor != null) { cursor.close(); } } }
方法四:
SQL 语句:
select a.date,a.snippet,c.type,b.address from threads a,canonical_addresses b , sms c where a.recipient_ids = b._id and c.date = a.date and c.thread_id = a._id and c.body >= a.snippet group by b.address order by a.date desc -- from sms
改变查询策略,查询表threads ,canonical_addresses ,sms
但是无法导出彩信记录
注意:sql语句中的"--"代表注释,所以
select a.date,a.snippet,c.type,b.address from threads a,canonical_addresses b , sms c where a.recipient_ids = b._id and c.date = a.date and c.thread_id = a._id and c.body >= a.snippet group by b.address order by a.date desc -- from sms
等同于
select a.date,a.snippet,c.type,b.address from threads a,canonical_addresses b , sms c where a.recipient_ids = b._id and c.date = a.date and c.thread_id = a._id and c.body >= a.snippet group by b.address order by a.date desc
所以上面的sql语句是一个很巧妙的方式满足了在ContentResolver 中查询也能够允许自定义的sql语句
void getSmsData(Context cnt) { ContentResolver resolver = cnt.getContentResolver(); Cursor cursor = null; try { cursor = resolver.query(Sms.CONTENT_URI,new String[] { " a.date,a.snippet,a.type", " b.address from threads a", " canonical_addresses b", " sms c where a.recipient_ids = b._id and c.date = a.date and c.thread_id = a._id and c.body >= a.snippet group by b.address order by a.date desc -- ", }, null, null, null); // 提高cursor访问速度 if (cursor != null) { int count = cursor.getCount(); cursor.moveToFirst(); synchronized (mImportDataList) { for (int i = 0; i < count; i++) { cursor.moveToPosition(i); long smsDate = cursor.getLong(0);//设置最新一条短信的时间 String smsBody = cursor.getString(1); // 內容 String phoneNum = cursor.getString(3); // 电话号码 int smsType = cursor.getInt(2); // 短信类型 Log.i("DEBUG", "smsDate = " + smsDate + ",smsBody=" + smsBody + ",phoneNum=" + phoneNum + ",smsType=" + smsType); } } cursor.close(); } } catch (Exception e) { Log.w(TAG, e.toString()); cursor = null; } finally { if (cursor != null) { cursor.close(); } } }
方法五:
终极大招,牛逼的SQL语句:
select address,date,body,type from (select a.address as address,c.date as date
,b.snippet as body,c.type as type from canonical_addresses a,threads b
, sms c where a._id = b.recipient_ids and b._id = c.thread_id and c.body >= b.snippet and c.date = b.date union
select c.address as address,b.date as date,a.sub as body,a.msg_box
as type from pdu a,threads b,canonical_addresses
c where a.thread_id = b._id and b.recipient_ids = c._id ) group by address order by date desc
它即能够导出sms、mms、草稿等。
void getSmsData(Context cnt) { ContentResolver resolver = cnt.getContentResolver(); Cursor cursor = null; try { cursor = resolver.query(Sms.CONTENT_URI,new String[] { "date,body,type, address from (select a.address as address,c.date as date", "b.snippet as body,c.type as type from canonical_addresses a,threads b , sms c where a._id = b.recipient_ids and b._id = c.thread_id and c.body >= b.snippet and c.date = b.date union select c.address as address,b.date as date ,a.sub as body,a.msg_box as type from pdu a,threads b,canonical_addresses c where a.thread_id = b._id and b.recipient_ids = c._id ) group by address order by date desc --", }, null, null, null); // 提高cursor访问速度 if (cursor != null) { int count = cursor.getCount(); cursor.moveToFirst(); synchronized (mImportDataList) { for (int i = 0; i < count; i++) { cursor.moveToPosition(i); long smsDate = cursor.getLong(0);//设置最新一条短信的时间 String smsBody = cursor.getString(1); // 內容 String phoneNum = cursor.getString(3); // 电话号码 int smsType = cursor.getInt(2); // 短信类型 Log.i("DEBUG", "smsDate = " + smsDate + ",smsBody=" + smsBody + ",phoneNum=" + phoneNum + ",smsType=" + smsType); } } cursor.close(); } } catch (Exception e) { Log.w(TAG, e.toString()); cursor = null; } finally { if (cursor != null) { cursor.close(); } } }
综上所述:
使用方法五即简单也能够满足需求和解决边界值问题。所以使用方法四来导入最新短信记录。
注意:由于为了让内容能够在网页里面显示,有一些代码是直接换行了,copy出去后,编译不过会报错。你只要把换行删掉就可以了。