可以在Android上发定时短信

  定时短信的界面比较简单,只是几个EditText和Button,功能包括添加联系人,编写短信,设定时间,保存发送等。Android号称拥有四大组件:Activity、Intent、Broadcast和Service。只要熟练掌握了这四大组件,Android开发就变得很简单了。在这个项目中,我用到了前三个,Service没有用到。Activity可以理解为一个窗口或者容器,它是可视化的,里面可以承载各种控件。对于Intent和Broadcast会在后面介绍。

  时间的设定是通过android.app.TimePickerDialog类来实现,这个类提供了一个可视化的窗口,对于用户来说界面十分友好。

  Android里的数据存储有三种方式。Android中的数据全部都是私有的,但是不同程序之间还是可以互相传递数据,那么Android是怎么做到的呢?原来Android中有一个ContentProvide,ContentProvide是来封装数据的,外界的程序可以通过 ContentProvide 的接口访问数据。Android中使用的是SQLite这个轻量级的嵌入式数据库。这个数据库对于硬件的要求很低,而且占用内存很小,但是速度很快,在嵌入式设备中被广泛应用。不过由于定时短信中需要存储的仅仅是联系人电话和编写的短信,所以我选择了另一种存储方式,那就是SharedPreferences。SharedPreferences提供了一种简单的,键值对的存储方式。一般用来存储一些简单的,少量的数据,存储一条短信再合适不过了。    

  完成这个小软件,必须解决的问题就是当设定好时间软件关闭后,时间到达时软件能够重新启动发送短信。实现这个功能的是Android里的闹钟唤醒。在android.app.AlarmManager类中提供了一种机制,使程序可以访问到系统的闹铃服务,这样应用程序就可以设定在未来的某个时间点执行。当到达那个时间点时,系统将Broadcast一个Intent来启动注册了闹铃服务的程序。 Intent在官方文档中是这样定义的:An intent is an abstract description of an operation to be performed.可以理解成Intent是对即将要执行的动作的抽象描述。在这里,我主要是把Intent给Broadcast 出去,然后在新建一个BroadcastReceiver 来接收,时间到达时开启一个新的Activity来发送短信。

  发送短信需要新建一个Activity,在本Activity里面只需使用 SmsManager这个类就可以了,这个类提供了发送短信的方法。在短信发出之后,一定要记着关掉这个发送短信的Activity,因为这个Activity的生命周期是0,发送完短信之后就没有必要存在了,使用finish()方法就可以了。

  这就是这个软件实现的主体思想,但是这样粗略地完成之后还有很多问题,比如在时间设定上,如果设定的时间已经过去,那么点击保存发送之后信息会立即发送;编写好的短信在发送之前仍然不能够查看和编辑;发送号码一栏里只能手动输入号码,不能从通讯录导入... 

    于是,我把主要的精力用在了软件的完善上。时间设定的问题比较容易解决,只要在点击短信保存按钮时对时间的合理性进行判断即可。但是在点击短信保存按钮的方法中已经不能获取设定的时间了,因此必须在点击设置时间的按钮里进行时间的判断,然后通过一个变量根据时间的合理性进行变化,在点击保存短信的方法中对这个变量进行判断,看看时间的设定是否满足要求。需要注意的是,这里系统时间的获取仍然是采用Java的语法,即final Calendar ca = Calendar.getInstance();int hours = ca.get(Calendar.HOUR);int minutes=ca.get(Calendar.MINUTE);这样就出现了一个小问题。众所周知,Java语言获取的系统时间是12小时制的,也就是说如果系统时间为14:00,那么用户设定8:00显然是不允许的,因为定时短信只能在一天之内发送,8:00代表早上八点,已经过去了。但是系统获取到的时间小时数却是2,因为获取系统时间为12小时制,通过比较8>2,时间设置看似没问题,但实际上时间设置是不正确的。所以还应当通过判断ca.get(Calendar.AM_PM)的值来得知是上午还是下午,如果是下午的话,小时数还应当再加上12。

  相对于时间问题,短信的保存就显得很简单了,只要在主Activity里再SharedPreferences一次就可以了,然后在短信发送成功之后把值再变为空。

  在整个软件的制作过程中,我遇到的最大问题就是联系人的导入。我前面说过,Android sdk更新的速度很快而且变化很大,这一点在通讯录方面尤为明显!由于我使用的是最新的Android sdk 2.2,可是有关读取通讯录联系人的资料都是使用Android sdk 1.5的API写的,当我在Android sdk 2.2下使用Android sdk 1.5的API时,Eclipse就会提出警告说不建议。没办法,我只能重新学习Android sdk 2.2里面相关的API。二者的API发生了变化,在之后与ListView进行适配时也出现了很多问题。对于联系人的读取都是获取光标实例,然后通过query()方法根据Uri读取,即Cursor c= getContentResolver().query(Phones.CONTENT_URI, null,null, null, null);不同的是,在Android sdk 2.2中Phones.CONTENT_URI变成了ContactsContract.Contacts.CONTENT_URI,另外读取联系人的姓名和电话号码也不同。怪不得有人说做Android开发很痛苦,因为要考虑不同版本之间的兼容性问题。这也没办法,Android系统毕竟是一个新的系统,在成熟性方面还不能与Symbian和WM相比。不过在现在看来,Android更新的速度已经降下来了,而且以后应该也不会出现API大幅的变化了。开发人员应该放心了!之后就是与ListView进行适配,把联系人信息显示在ListView中,在ListView的点击方法中把存储的联系人电话号码传到主Activity中。数据的传递又要使用到Intent,只不过与之前简单的跳转不同,这次的跳转需要获取数据,startActivity()变成了startActivityForResult()。

  这样,整个程序就相对完善了。当然这个小软件还存在很多问题,比如不能跨天发短信等,界面也不是很友好。这些问题的解决还需要我不断地去钻研和尝试。通过这一个小程序,我认识到自己的Android开发之旅才刚刚起步。不过我也发现Android手机不仅能够吸引用户,因为大家都说Android手机是玩机的最佳选择,而且在这上面做开发也是一种很棒的感觉,因为它提供了一套很优秀很强大的开发工具。借着开源世界强大的Eclipse和Java语言之风,我们有理由相信这个小绿人会飞得越来越高,越来越远...

 

  主程序除了在onCreat()中创建两个EditText控件与一个Button控件外,分别设置onClickLinstener()让用户单击EditText控件时,同时清除内容,在单击Button时送出短信,并通过isPhoneNumberValid()与iswithin70()这两个自定义的方法来检查收件人电话号码的正则表达式,以及短信正文的字数是否超过70个字符。

  在两项检查同时通过的前提下,通过PendingIntent.getBroadcast()的方法自定义PendingIntent并进行Broadcasting,而后使用SmsManager.getDefault()(当处理SMS短信相关的活动,例如发送数据、文字与pdu SMS信息,都需要调用这种静态的方法)所预先构建的SmsManager使用sendTextMessage()方法,将相关数据以参数带入,即可完成发送短信的任务。

 

  1. /*检查字符串是否为电话号码的方法,并返回true or false的判断值*/  
  2.   
  3.   public static boolean isPhoneNumberValid(String phoneNumber)  
  4.   
  5.   {  
  6.   
  7.     boolean isValid = false;  
  8.   
  9.     /* 可接受的电话格式有: 
  10.  
  11.      * ^//(? : 可以使用 "(" 作为开头 
  12.  
  13.      * (//d{3}): 紧接着三个数字 
  14.  
  15.      * //)? : 可以使用")"继续 
  16.  
  17.      * [- ]? : 在上述格式后可以使用具有选择性的 "-". 
  18.  
  19.      * (//d{3}) : 再紧接着三个数字 
  20.  
  21.      * [- ]? : 可以使用具有选择性的 "-" 继续. 
  22.  
  23.      * (//d{5})$: 以五个数字结束. 
  24.  
  25.      * 可以比较下列数字格式: 
  26.  
  27.      * (123)456-7890, 123-456-7890, 1234567890, (123)-456-7890   
  28.  
  29.     */  
  30.   
  31.     String expression =   
  32.   
  33.     "^//(?(//d{3})//)?[- ]?(//d{3})[- ]?(//d{5})$";  
  34.   
  35.     CharSequence inputStr = phoneNumber;  
  36.   
  37.     /*创建Pattern*/  
  38.   
  39.     Pattern pattern = Pattern.compile(expression);  
  40.   
  41.     /*将Pattern 以参数传入Matcher作Regular expression*/   
  42.   
  43.     Matcher matcher = pattern.matcher(inputStr);  
  44.   
  45.     /*创建Pattern2*/  
  46.   
  47.     Pattern pattern2 =Pattern.compile(expression2);  
  48.   
  49.     /*将Pattern2 以参数传入Matcher2作Regular expression*/   
  50.   
  51.     Matcher matcher2= pattern2.matcher(inputStr);  
  52.   
  53.     if(matcher.matches()||matcher2.matches())  
  54.   
  55.     {  
  56.   
  57.       isValid = true;  
  58.   
  59.     }  
  60.   
  61.     return isValid;   
  62.   
  63.   }  
  64.   
  65.     
  66.   
  67.   public static boolean iswithin70(String text)  
  68.   
  69.   {  
  70.   
  71.     if (text.length()<= 70)  
  72.   
  73.     {  
  74.   
  75.       return true;  
  76.   
  77.     }  
  78.   
  79.     else  
  80.   
  81.     {  
  82.   
  83.       return false;  
  84.   
  85.     }  
  86.   
  87.   }  
  88.   
  89. }  
AndroidManifest.xml

请注意,需要添加发送短信的权限android.permission.SEND_SMS。

扩展学习

//取得android系统中默认的短信管理器
SmsManager manager=SmsManager.getDefault();
//如果短信内容过长时,则对短信内容进行拆分
ArrayList<String> texts=manager.divideMessage(content);
for(String text:texts){
//第一个参数:对方手机号码
//第二个参数:短信中心号码,一般设置为空
//第三个参数:短信内容
//第四个参数:sentIntent判断短信是否发送成功,如果你没有SIM卡,或者网络中断,则可以通过这个intent来判断。
//注意强调的是“发送”的动作是否成功。那么至于对于对方是否收到,另当别论
//第五个参数:当短信发送到收件人时,会收到这个deliveryIntent。即强调了“发送”后的结果
//就是说是在"短信发送成功"和"对方收到此短信"才会激活sentIntent和deliveryIntent这两个Intent。这也相当于是延迟执行了Intent
manager.sendTextMessage(mobile,null, text,null,null);
}
//Toast.makeText(getApplicationContext(), "发送成功", Toast.LENGTH_LONG).show();
Toast.makeText(MainActivity.this,"发送成功",Toast.LENGTH_LONG).show();
}

本范例使用到的PendingIntent对象,具有下列的特性:当接收到PendingIntent对象时,会进行broadcast的动作,就如同使用Context.sendBroadcast()方法一样,这也就是为什么在SmsManager.sendTextMessage()方法中需要传入PendingIntent作为传送服务的参数之一。

在主程序中使用发送短信的方式,只展示了SmsManager类中,可使用的3种传送短信的方法之一,而完整的3种可用方法,整理如表5-1所示。

表5-1                                     SmsManager类中可使用的3种方法

方 法 名 称

传 入 参 数

使 用 时 机

sendDataMessage

String destinationAddress, String scAddress, short destin-
ationPort, byte[] data, PendingIntent sentIntent, Pending
Intent deliveryIntent

发送Data格式的SMS传送到特定程序的Port

sendMultipartTextMessage

String destinationAddress, String scAddress, ArrayList 
<String> parts, ArrayList<PendingIntent> sentIntents, 
ArrayList<PendingIntent> deliveryIntents

发送多条文字短信

sendTextMessage

String destinationAddress, String scAddress, String text, 
PendingIntent sentIntent, PendingIntent deliveryIntent

发送文字短信

 

另外,本范例并没有实现接收sms的部分,仅发出短信,由于单纯通过运行程序的模拟器,将无法了解短信是否真的有送出,而收件人是否真的有收到。因此,在程序开发的过程中,读者可以通过下面的小技巧来打开两个模拟器,一个进行传送,另一个进行收件的模拟测试。

步骤一:先进入Eclipse,compile运行程序,并顺利开始第一个模拟器实例(Instance)。

步骤二:打开DOS窗口(cmd),并输入命令,进入文件夹:

D:/>cd D:/SDK/android/tools/

步骤三:输入shell command,其中foo为AVD的名称。

D:/SDK/android/tools>emulator -data foo

此时,窗口会跳出另一个模拟器,通过输入左上方的InstanceID(例:5546)作为收件人的电话号码,即可测试短信送达的状态。

最后提到了拆分短信,此范例中虽然自制了简单的判断字符串字符数,却只能接受单则的短信,事实上,在SmsManager里尚有一个公有方法:

public ArrayList<String> divideMessage (String text)

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package com hmm test820; import java util Scanner; public class SMS { public SMS { } public Student[] stu new Student[10]; public void add Student[] stu Student s { System out println "增加一个学生 " ; System out println Student count ; Student count++; this stu[Student count 1] s; } 删除操作 public void delete Student[] stu String id { int index 0; for int i 0;i<Student count;i++ { if id equals stu[i] id { index i; } } Student count ; System out println Student count ; for int i index;i<Student count;i++ { stu[i] stu[i+1]; } } 修改学生信息 public void update Student[]stu String id String name String age String job { System out println "修改学生信息 " ; for int i 0;i<Student count;i++ { if id equals stu[i] id { this stu[i] name name; this stu[i] age age; this stu[i] job job; } } } 查看单个学生信息 public void query Student[]stu String id { System out println "查看单个学生信息 " ; for int i 0;i<Student count;i++ { if id equals stu[i] id { System out println stu[i] id+" t t"+stu[i] name+" t t"+stu[i] age+" t t"+stu[i] job ; } } } 查看学生信息 public void display Student[]stu { for int i 0;i<Student count;i++ { System out print stu[i] id+" t t"+stu[i] name+" t t"+stu[i] age+" t t"+stu[i] job ; System out println ; } } 界面显示部分 登录界面首页显示 public static void print1 { System out println " n n t t欢迎使用学生信息管理系统2 0版 n" ; System out println " n n" ; System out println " t t t t1 登录系统 n n" ; System out println " t t t t2 退出 n n" ; System out println " n n" ; System out print "请选择 请输入数字:" ; } 成功登录后显示部分 public static void print2 { System out println "欢迎使用学生信息管理系统2 0版" ; System out println " " ; System out println " t t t t1 查看当前学生信息" ; System out println " t t t t2 添加学生信息" ; System out println " t t t t3 修改学生信息" ; System out println " t t t t4 查询学生信息" ; System out println " t t t t5 删除学生信息" ; System out println " t t t t6 退出" ; System out println " " ; } public static void printmessage { System out println "请输入学号 姓名 年龄 职位:" ; } public static void printid { System out println "请输入学号:" ; } public static void printnext { System out print "请继续选择您的操作(输入0返回上一菜单):" ; } public static void printlogin { System out print "请输入登录账号:" ; } public static void printps { System out print "请输入密码:" ; } public static String message { Scanner s new Scanner System in ; String str s next ; return str; } public static void printerror { System out println "input error" ; } public static int inputcount { Scanner s new Scanner System in ; int count s nextInt ; return count; } public static void main String[] args { SMS sms new SMS ; Student s new Student "001" "23" "32" "323" ; boolean flag1 true; while flag1 { print1 ; switch inputcount { case 1: { Student s new Student ; printlogin ; String login message ; printps ; String pw message ; print2 ; if login equals "login" &&pw equals "1" { print2 ; printnext ; boolean flag2 true; while flag2 { switch inputcount { case 1: { sms display sms stu ; printnext ; break; } case 2: { printmessage ; s id message ; s name message ; s age message ; s job message ; s new Student s id s name s age s job ; sms add sms stu s ; printnext ; break; } case 3: { printmessage ; s id message ; s name message ; s age message ; s job message ; s new Student s id s name s age s job ; sms update sms stu s id s name s age s job ; printnext ; break; } case 4: { printid ; s id message ; sms query Student[]stu String id ; printnext ; break; } case 5: { printid ; s id message ; sms delete sms stu s id ; printnext ; break; } case 6: { flag1 false; break; } default: { printerror ; break; } } } } break; } case 2: flag1 false; break; default: printerror ; break; } } } }">package com hmm test820; import java util Scanner; public class SMS { public SMS { } public Student[] stu new Student[10]; public void add Student[] stu Student s { System out println "增加一个学生 " ; System out println Student count ; Student count++; t [更多]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值