常逢佳,韦相和,董泉灵
(淮阴师范学院 计算机科学与技术学院,江苏 淮安 223300)
Strategy Analytics发布的最新研究报告分析指出,2013年全球智能手机出货量创新高达到9.9亿台,比上年增长41%,Android占据79%的市场份额,拉开了与苹果iOS、微软Windows Phone和其他操作系统的差距。[1]
在国内,互联网消费调研中心(ZDC.zol.com.cn)2013年10月中国智能手机市场不同操作系统产品均价对比调查显示[2],随着智能手机平均售价差距进一步拉大,Android手机均价越来越低,而i-Phone均价虽然也逐年走低,但与Android手机的均价差距却越来越大(如表1所示)。
表1 2013年10月中国智能手机市场产品均价对比
目前,以火狐OS、三星Tizen、旗鱼操作系统为代表的云智能手机操作系统,其宽泛的应用程序及成本低廉等优点,是传统手机系统无法比拟的。云操作系统尚处于萌芽,未来很有希望获取大量的市场份额[3]。目前市场上的云手机无一例外都采用了Android操作系统。在这种情况之下,Android在全球智能手机操作系统市场上的份额将持续走高。
手机的通信服务有很多种,其中短信服务是最基本的。通过短信服务,用户可以收发个人和商业信息。但目前智能手机中的短信管理方式单一,查询功能也不是很健全,主要是根据联系人和收发短信的时间先后进行显示及管理。这就带来了一些问题,随着短信数目的增加,用户若要查找到目标短信,必须浏览联系人的每一条短信以查找到目标短信,查询效率低。如果忘记了具体的发信人,那必须查看每位联系人,如此查找到目标短信的效率就更低。如文献[4]所述,顺序查找的时间复杂度为O(n)。所以,目前的智能手机需要一个能够高效管理短信的第三方软件来解决上述问题。
综上所述,本文以Android系统为平台,设计了一套短信高效管理方案来解决手机短信管理中的问题。
Android的系统短信数据库在/data/data/com.android.providers.telephony/databases/mmssms.db中,利用SQLite Expert Professional 3查看,发现其中共有17 张表:addr、android_metadata、attachments、canonical_addresses、drm、part、pdu、pending_msgs、rate、raw、sms、sr_pending、threads、words、words_content、words_segdir、words_segments。[5]
其中本方案涉及的表[6]主要有:
(1)sms表存储所有短信息数据的,主要的字段、字段类型及字段说明见表2。
表2 sms表字段、字段类型及说明
(2)threads表存储着每一个短信对话的线程,主要字段、字段类型及字段说明见表3。
表3 threads表字段、字段类型及说明
(3)canonical_addresses表存储短信会话的联系人号码。主要字段、字段类型及字段说明见表4。
表4 canonical_addresses字段、字段类型及说明
sms表的thread_id与threads表的_id相对应,threads表的recipient_ids与canonical_addresses表的_id相对应。[6]
Android系统是通过内容提供者(Content-Provider)向应用提供访问底层数据库数据的。应用程序可以通过一个Uri(Uniform Resource Identifier)访问对应的数据。短信管理的数据存储主要依赖三个 ContentProvider:SmsProvider、MmsProvi-der、MmsSmsProvider,以及一个辅助类 Telephony。
其中,SmsProvider用于短信相关数据的存取,MmsProvider用于彩信相关数据的存取,MmsSmsProvider则用于短彩信通用数据的存取,如会话列表、收件箱、草稿(公共属性)等。[7]
Telephony则提供了一系列Uri、常量字符串、列名数组、方法等,进而方便用户使用这些内容提供者。
例如:对短信进行分类管理时,利用sms表的Uri有
收件箱:URI_SMS_INBOX=Uri.parse("content://sms/inbox").
发 件 箱 :URI_SMS_OUTBOX=Uri.parse("content://sms/outbox").
草稿箱:URI_SMS_DRAFT=Uri.parse("content://sms/draft").
查询 conversations信息:URI_SMS_CONVERSATION=Uri.Parse("content://sms/conversations")
查询相关短信联系人时,查询了threads表的uri:MSG_QUERY_URI=?Uri.parse ("content://mms-sms/conversations??simple=true")。
查 询 canonical_addresses 表 的 uri:MMS_SMS_ADDRESS_URI?=Uri.parse ("content://mms-sms/canonical-addresses").
对于数据表的访问,在Android中采用游标方式。如果通过Activity类的managedQuery(uri,projection,selection,selectionArgs,sortOrder) 去直接查询管理游标(cursor),就是在主线程中进行。数据量大时,查询速度慢,容易出现ANR(Application Not Response应用程序无响应)异常。因此,在方案设计时,采用Android提供的异步框架AsyncQueryHandler去访问ContentProvider所提供的数据。
在Android开发中,若要访问系统短信数据库中的数据,需要添加访问权限。该方案设计中,需要添加的权限如下:
读短信权限:<uses-permission android:name="android.permission.READ_SMS"/>。
读联系人权限:<uses-permission android:name="android.permission.READ_CONTACTS"/>。
写短信权限:<uses-permission android:name="android.permission.WRITE_SMS"/>。
发送短信权限:<uses-permission android:name="android.permission.SEND_SMS"/>。
要想提高短信管理系统的开发及运行效率可以从以下几个方面考虑。
在Android系统中,当我们使用ContentProvider操作数据库时,如果数据量很小,是没有问题的;但如果数据量大,应用在6秒内没有对其进行任何处理,UI线程就会出现ANR异常(Application Not Response应用程序无响应)。因此,我们通常将比较耗时的操作放在新线程中执行。
如果应用需要操作界面,可以使用Handler进行处理。只是每次使用ContentProvider时都要再写一个Handler,这样必然降低了程序执行效率。API提供了一个操作数据库的通用方法——异步查询操作帮助类AsyncQueryHandler,它也可以处理数据的增删改操作。
AsyncQueryHandler 中提供了 startInsert、start-Delete、startUpdate、startQuery 四项操作,并提供了相对应的onXXXComplete方法,以供操作完数据库后进行其它的操作,这四个onXXXComplete()方法都是空实现,以便我们只需实现所关注的操作。[8]
在本方案中,定义了QueryHandler,继承了AsyncQueryHandler,提供了 onQueryComplete(int token,Object cookie,Cursor cursor)方法的实现,并通过Adapter使数据发生改变。
在显示短信列表时,定义了startQuery()方法,其中使用了AsyncQueryHandler中的mQueryHandler.startQuery() {
Uri uri=Sms.CONVERSATION_URI;
if(thread_ids!=null){
String where=Sms.THREAD_ID+"in"+thread_ids;
mQueryHandler.startQuery (0,null,uri,CONVERSATION_PROJECTION,where,null,"datedesc");}else {mQueryHandler.startQuery(0,null,uri,CONVERSATION_PROJECTION,null,null," date desc");}}方法。
因此,在用户短信信息量不断增多的情况下,避免了ANR异常的出现,同时提高了应有程序的运行效率。
由表2可知通过一条短信的日期、时间、发送人、接收人等多种属性可以进行查询定位。
目前智能手机基本上都有根据通信录查询的功能。用户在查找前先根据短信关联的联系人,列出与该联系人的所有短信,并且所有的短信按照时间在后排在前的顺序显示。其次,根据短信内容进行全文搜索查询。这样用户在记不清联系人及短信时间时,可以搜索关键字,对所有的短信内容进行定位,由此提高了查找效率。
Android系统自身就有一个功能健壮的全局搜索模块,因此,在方案设计时,为了提高开发效率,就利用了Android系统自身的搜索模块功能。具体操作步骤如下:
(1)首先,必须在工程的 res/xml/下创建searchable.xml文档,具体内容如下:
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
android:label="@string/sms_search"android:hint="@string/sms_search"
android:searchSuggestAuthority="PackageNamePath.MySuggestionProvider"
//给提供查询信息服务的ContentProvider
android:searchSuggestSelection="?" >
//要搜索的关键字
</searchable>
(2)定义提供搜索界面的SearchableActivity
……
if(Intent.ACTION_SEARCH.equals(intent.getAction())){
String query=intent.getStringExtra(SearchManager.QUERY);
//自己的搜索操作
doMySearch(query);
……
对于上面的界面中必须引用自己定义的查询搜索函数 private void doMySearch(String query){
Uri uri=Sms.CONTENT_URI;
String selection=Sms.BODY+"like'%"+query+"%'";
mQueryHandler.startQuery(0,null,uri,SMS_PROJEC
TION,selection,null,Sms.DATE+"desc");
};}
否则,系统会调用默认的搜索功能。
(3)在清单文件中注册
<activity android:name="com.example.SearchableActivity">
<intent-filter>
<action android:name = "android.intent.action.
SEARCH"/>
</intent-filter>
<meta-data android:name="android.app.
searchable" android:resource="@xml/
searchable"/></activity>
点击搜索功能时,则默认调用系统搜索模块。若要让短信管理中的每个Activity界面中都能使用短信搜索功能,则必须在清单文件中添加<metadata
android:name="android.app.default_searchable"
android:value=".SearchableActivity"/>
否则,跳过自身定义搜索模块。
(4)定义提供搜索功能的ContentProvider需要重写其中的
public Cursor query(Uri uri,String[]projection,String selection,
根据用户输入的信息,到sms表中的BODY字段中查找关键字
Uri uri1=Sms.CONTENT_URI;
String where=Sms.BODY+"like'%"+query+"%'";
并利用游标返回查找到的结果
Cursorcursor= getContext().get-ContentResolver().query(uri1,sms_projection,where,null,Sms.DATE+"desc");
return changeCursor(cursor);}
return null;}
按上述步骤操作即可完成对短信全文搜索功能的实现。用户对于一些重要短信可以直接利用关键字查找,大大提高了用户查找短信的效率,同时也提高了短信管理系统的开发效率。
为了方便对短信进行管理,用户可以根据个人情况建立群组,个性化的对短信进行分类管理[9]。
(1)首先创建 smsmanager.db库,其中包含groups和thread_groups两张表。groups表保存群组信息,thread_groups表保存每个群组中包含的短信息的记录。具体包含的字段及字段说明如下表5、表6所示。
表5 Group表字段、字段类型及说明
(2)数据的访问
在系统中提供了SmsManagerProvider,方便对群组数据进行访问。
public Cursor query(Uri uri,String[]projectionIn,String selection,
String[]selectionArgs,String sortOrder)方法中设置了一个模式匹配器,根据传递来的URI进行判断
int code=matcher.match(uri);
switch(code) {
case GROUPS:
qb.setTables("groups");
qb.setProjectionMap(mGroupsProjectionMap);
break;
case THREAD_GROUPS:
qb.setTables("thread_groups");
qb.setProjectionMap (mThread-GroupsProjectionMap);
break;
default:
throw new IllegalArgumentException("没有匹配的 uri"+uri);
}
如果出现相同的群组名或者相同的短信thread_id添加到同一群组中时,则提示错误信息,否则可创建新的群组和添加新的短信到群组中。
在Eclipse下建立工程。应用运行的主界面如图1所示。界面主要由会话,文件夹,群组三个选项卡组成。[10]
图1 会话选项卡界面
会话选项卡中主要包括:(1)短信列表:针对列表中的短信,可以直接进行点击查看、菜单删除、编辑等操作;(2)新建信息:点击按钮,直接实现创建短信及发送等功能。快捷菜单中提供了搜索功能,可以对短信进行全文搜索。
文件夹选项卡主要包括收件箱、发送箱、已发送、草稿箱等。用户可以在不同文件夹中对短信进行分类查找,在相同的类别视图下短信息依据日期进行分隔显示。界面如图2、图3所示。
图2 文件夹选项卡界面
群组选项卡中初始状态是空白的,用户点击快捷键弹出新建群组名称,可以根据自身的需要创建群组名。群组创建好后,可以利用快捷键向对应的群组中添加短信。界面如图4所示。
图3 收件箱界面
图4 群组选项卡界面
通过前面的设计分析和实验结果,表明使用该方案用户能有效地管理Android系统中的短信息。可以快速找到需要的短信,查询效率比顺序下翻方式提高了很多;同时还允许用户查找内容关键词,这是很多手机短信管理程序都没有的功能;用户还可以根据自己的需要建立个性化群组,对短信进行分类管理。
此外,文中还介绍了Android的系统信息库,为广大Android应用程序的开发者提供了一定的借鉴与参考。
[1]Gnaix.2013年Android智能手机全球市场份额达79%[EB/OL].(2014-02-09)[2014-09-12].http://mobile.chinabyte.com/497/12852997.shtml.
[2]王彦恩.2013年10月中国智能手机市场分析报告[EB/OL].(2013-11-13)[2014-09-12].http://zdc.zol.com.cn/411/4119456_all.html.
[3]网易科技报道.专家表示云手机即将威胁Android和iPhone 市场[EB/OL].(2013-9-16)[2014-09-10].http://tech.163.com/13/0916/05/98SCGUUC000915BD.html.
[4]霍静,毛晓蛟,严善春.基于Android的高效短信查询软件的实现[J].数据库与信息管理,2010(10):55-56.
[5]刘安战,贾晓辉.基于Android的私密短信系统设计与实现[J].微型机与应用2012,31(17):51-52.
[6]zhangzh332.Android中短信数据库的简单操作[EB/OL].(2011-05-05)[2014-09-10].http://blog.csdn.net/zhangzh332/article/details/6396985.
[7]李刚.疯狂 android讲义[M].北京:电子工业出版社,2011:400-404.
[8]t12x3456.Android异步查询框架AsyncQueryHandler的使用[EB/OL].(2012-08-28)[2014-09-10].http://www.2cto.com/kf/201208/151114.html.
[9]笪林梅.基于Android的手机通讯录管理系统的研究与实现[J].郑州轻工业学院学报(自然科学版),2013(3):61-64.
[10]倪红军,钱昌俊.基于Android平台的自发短信系统设计与实现[J].电子技术应用.2012,38(12):126-128.