可以在Android上發定時簡訊

來源:互聯網
上載者:User
文章目錄
  • 擴充學習

  定時簡訊的介面比較簡單,只是幾個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()這兩個自訂的方法來檢查收件者電話號碼的Regex,以及簡訊本文的字數是否超過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)

 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.