Android2.1消息應用(Messaging)源碼學習筆記(轉載)

我想首先應該從AndroidManifest.xml 文件開始,該文件是Android應用(APK)的打包清單,其中提供了關於這個應用程序的基本信息,如名稱(application/@label),圖標( application/@icon ),等常量信息,但該文件最重要的功能仍然是:向Android系統聲明應用程序所包含的組件,包括Activity、Service、Receiver和ContentProvider,另外還會請求 系統 授予相關權限。

 

<application>是重要的標記,通常我們都是在此設置應用程序的名稱和圖標,而在Messaging這個應用中,它擴展了默認的android.app.Application類,在com.android.mms.MmsApp類中覆寫了onCreate()方法進行系統初始化、覆寫onTerminate() 方法做相關清理工作。最重要的是<application>標記設置了(任務吸引力) taskAffinity=“android.task.mms”、allowTaskReparenting ="true" 這是兩個與 Task有關的屬性,那麼何爲任務(Task)呢?

 

A pplication就是一個.apk文件,由若干個組件(可能會包括 Activity、Service、Receiver 或者ContentProvider )構成,它是一個物理上的獨立存在。而Task則是指用戶藉助Application提供的功能完成某件事情,例如:發送一條信息給老朋友。通常一個Task操作所涉及的內容不會超過 A pplication邊界 ,但在Android中卻不是這樣,Android允許一個Task操作 橫跨多個Apllication。還以向老朋友發送信息爲例,在該任務中,至少需要一個用來輸入目標電話號碼和消息內容的用戶界面——即Android中的Activity組件(這是 Messaging應用中的內容 ),如果進一步要求目標號碼是從聯繫人列表(或通話列表)中選擇,而非手工輸入,那麼就涉及到跨 Apllication調用‘聯繫人應用’中的列表組件  (也是一個 Activity  。因此以上兩個屬性前者設置了 Activity的吸引力(Affinity)值,後者使得 Activity可以在不同的Task中自有切換。

 

 

Messaging中的Receiver

R eceiver廣播 接收器用於響應系統中的各種廣播事件並執行相關業務代碼的組件,常用於完成如:啓動service、顯示Activity等 任務 。在Messagin應用中一共有7個 R eceiver:

1、.transaction.SmsReceiver : 短消息 廣播 接收器,它負責處理與收到短消息相關的廣播事件。觸發該接收器運行的intent有兩個:

A.android.intent.action.BOOT_COMPLETED--->Android系統啓動完成時會發出該廣播,即SmsReceiver會在系統啓動完成時接收到調用;

B.com.android.mms.transaction.MESSAGE_SENT --->定義在 SmsReceiverService.java中的常量,被用在SmsMessageSender.sendMessage方法中——即短消息發送後 觸發的廣播事件;

完全和預想的一樣,在 SmsReceiver中會啓動 SmsReceiverService,啓動代碼在beginStartingService方法裏。值得注意的是它同時還做了“屏幕喚醒鎖定 (WakeLock)” 操作,最終在service啓動完成後,通過回調用finishStartingService方法,解除了屏幕喚醒鎖定。

SmsReceiver.java中有編譯錯誤,因爲無法訪問android.provider.Telephony.Sms.Intents。其實 Intents 所在位置是:myeclair\frameworks\base\core\java\android\provider\Telephony.java,它被標記爲@hide。

 

2、 . transaction.PrivilegedSmsReceiver :該接收器是SmsReceiver的子類,唯一的區別在於該Receiver被申明有permission爲android.permission.BROADCAST_SMS。

 

 

3、.transaction.MmsSystemEventReceiver :Mms系統事件接收器,它負責 在收到新消息時 向通知區域(即標題欄)顯示小圖標,和 重新發送在發件箱中的MM。觸發該接收器運行的兩個Intent是:

A. android.intent.action.BOOT_COMPLETED ---> :與SmsReceiver中的情況相同;

B.android.intent.action.CONTENT_CHANGED ---> :連接方式改變時系統會發出該廣播,即在連接方式變化,例如從gprs-->wifi時該接收器將被調用 

在MmsSystemEventReceiver類中,程序一旦獲得數據連接時就會啓動TransactionService服務;當連接方式改變時還會調用PduCache.purge()方法清理緩存;還有當系統剛剛啓動時 會同步通知區域的圖標、未讀消息個數等信息。

MmsSystemEventReceiver.java中有編譯錯誤,因爲它無法訪問以下類:

1、com.google.android.mms.util.PduCache:位置-myeclair\frameworks\base\core\java\com\google\android\mms\util\PduCache.java,該類未包含在默認的android.jar文件中,需要重新編譯;

2、android.provider.Telephony.Mms: 位置- myeclair\frameworks\base\core\java\android\provider\Telephony.java,該類被標記爲 @hide 

3、com.android.internal.telephony.TelephonyIntents:位置-myeclair\frameworks\base\telephony\java\com\android\internal\telephony\TelephonyIntents.java,該類是一個常量類是未被開放的API。

4、com.android.internal.telephony.Phone: 位置- myeclair\frameworks\base\telephony\java\com\android\internal\telephony\Phone.java, 該類被標記爲 @hide 

 

4、.transaction.PushReceiver  WAP_PUSH 事件的廣播接收器,該事件發生時 代表手機收到了一條新的WAP PUSH message。該接收器被調用後,首先喚醒手機屏幕5秒鐘,然後在一個後臺線程中處理push-data,將消息數據插入到數據庫中,必要時啓動TransactionService服務以更新通知信息 。觸發該接收器運行的 Intent是:

(intent.action=android.provider.Telephony.WAP_PUSH_RECEIVED, data=application/vnd.wap.mms-message),其中Action.Name定義在android.provider.Telephony類中。值得注意的是該Receiver有申明權限:android.permission.BROADCAST_WAP_PUSH,這意味着發出該廣播時必須攜帶該授權,否則本 Receiver將不會被觸發執行。

PushReceiver.java中有編譯錯誤,因爲它無法訪問以下類:

1、android.provider.Telephony  位置- myeclair\frameworks\base\core\java\android\provider\Telephony.java,該類被標記爲 @hide 

2、com.google.android.mms.*: 位置- myeclair\frameworks\base\core\java\com\google\android\mms\*,這些類未包括在公開的API中。

 

5、. transaction.MessageStatusReceiver :消息狀態改變時的廣播接收器,消息狀態改變是指消息的投遞狀態(即:是否成功送達、是否被目標用戶閱讀等)的變化,觸發該接收器的Intent是:com.android.mms.transaction.MessageStatusReceiver. MESSAGE_STATUS_RECEIVED,該值是申明在MessageStatusReceiver.java文件中的常量。該廣播事件是在SmsMessageSender.sendMessage()方法中被髮出的,收到廣播事件後,Receiver的會做兩件事情:a-取得pdu數據包 更新消息狀態(在updateMessageStatus方法中);b-更新通知區域的新消息指示信息 (在MessagingNotification.updateNewMessageIndicator()方法中)。

MessageStatusReceiver.java中有編譯錯誤,因爲它無法訪問以下類:

1、android.provider.Telephony  位置- myeclair\frameworks\base\core\java\android\provider\Telephony.java,該類被標記爲 @hide 

2、com.google.android.mms.util.SqliteWrapper: 位置- myeclair\frameworks\base\core\java\com\google\android\mms\ util\SqliteWrapper.java,該類未包括在公開的API中。

 

6、.transaction.SimFullReceiver :Sim卡短信存儲空間滿的事件通知,當系統發現Sim卡中存儲短信的空間耗盡時會發出該廣播事件。該接收器完成的工作是在通知區域顯示相關信息,點擊通知信息後,可以進入管理Sim卡中短消息的Activity界面 

SimFullReceiver.java中有編譯錯誤,因爲它無法訪問 android.provider.Telephony 類,所在位置-myeclair\frameworks\base\core\java\android\provider\Telephony.java,該類被標記爲 @hide 


7、.transaction.SmsRejectedReceiver :短消息被拒絕時的事件接收器,當手機的存儲空間不足時會拒絕接收新的短消息,當該事件發生時SmsRejectedReceiver被調用,它會檢查確認是否是存儲空間不足,然後在通知區域顯示相關通知信息。

SmsRejectedReceiver.java中有編譯錯誤,因爲它無法訪問 android.provider.Telephony 類,所在位置-myeclair\frameworks\base\core\java\android\provider\Telephony.java,該類被標記爲 @hide 


 

Messaging中的Activity

Activity是用來構建UI(用戶界面 )的組件,用戶操作界面代表了應用程序提供的基本功能,是應用程序和用戶之間的交互接口。在Messaging應用中有以下的Activity:

1、.ui.ConversationList ,對話列表界面,這是進入應用程序的主界面。它有兩個配置屬性值得我們特別注意,a.android:configChanges="orientation|keyboardHidden":在Android系統中,當程序所運行的環境(如:屏幕方向、鍵盤狀態、字體等級,等等 )發生變化後 會導致Activity被重新啓動(以適應環境變化 ),然而 Activity也可以宣稱自己來應付某些變化(而不是一股腦地全讓系統重啓自己), configChanges 屬性 正是用於 指定自己願意 應付 的變化情況。此處該屬性有兩個值, orientation代表屏幕方向發生改變,keyboardHidden表示鍵盤可訪問狀態發生變化(即鍵盤彈出/收起 ),這意味着當屏幕方向和鍵盤可用狀態 發生變化時, Activity不會被重新啓動,而是調用其onConfigurationChanged方法,通常是在該方法中對自己做出調整,以適應變化;b.launchMode="singleTop":該屬性指示了Activity的加載模式,這與Activity在不同Task之間的重用有關,該屬性共有4個可用選項standard, singleTop,singleTask,singleInstance,它們將與Intent中的FLAG_ACTIVITY_* 標記 常量 協同產生相關作用。

ConversationList類中定義了程序中涉及到的選項菜單、會話(Conversation)項上的上下文菜單等UI元素。另外該類中的runOneTimeStorageLimitCheckForLegacyMessages方法用於檢測存儲空間限制。

SmsRejectedReceiver .java中有編譯錯誤,因爲它無法訪問以下類:

1.android.provider.Telephony 類,所在位置- myeclair\frameworks\base\core\java\android\provider\Telephony.java,該類被標記爲 @hide 

2. com.google.android.mms.*: 位置- myeclair\frameworks\base\core\java\com\google\android\mms\*,這些類未包括在公開的API中。


2、.ui.ComposeMessageActivity ,創建新消息的用戶界面,通過選項菜單menu_compose_new會調用到該界面。這是個很龐大的類,內部實現也很複雜,等仔細看了再寫補充吧。

ComposeMessageActivity .java中有編譯錯誤,因爲它無法訪問以下類:

1.com.android.internal.widget.ContactHeaderWidget類,所在位置-myeclair\frameworks\base\core\java\com\android\internal\widget\ContactHeaderWidget.java,該類被標記爲 @hide 

2.com.android.internal.telephony.* 類,所在位置- myeclair\frameworks\ base\telephony\java\com\android\internal\telephony\*,這些類未包括在公開的API中 

3. com.google.android.mms.*: 位置- myeclair\frameworks\base\core\java\com\google\android\mms\*,這些類未包括在公開的API中 

 

3、 .ui.ForwardMessageActivity ,用於轉發消息的Activity,這是ComposeMessageActivity的別名,用於把一條現有消息的內容帶到創建消息的界面上;

 

4、.ui.DeliveryReportActivity ,投遞報告 Activity, 用於報告消息的投遞狀態,它採用對話框風格的主題(android:theme="@android:style/Theme.Dialog")。

DeliveryReportActivity .java中有編譯錯誤,因爲它無法訪問以下類:

1. com.google.android.mms.*: 位置- myeclair\frameworks\base\core\java\com\google\android\mms\*,這些類未包括在公開的API中 

2. android.provider.Telephony 類,所在位置- myeclair\frameworks\base\core\java\android\provider\Telephony.java,該類被標記爲 @hide 

 

5、.ui.WarnOfStorageLimitsActivity ,存儲空間限制警告,用於告知用戶 關於存儲空間限制的設置信息。

WarnOfStorageLimitsActivity .java中有編譯錯誤,因爲它無法訪問以下類:

1. com.android.internal.app.AlertActivity類, 位置- myeclair\frameworks\base\core\java\com\android\internal\app\AlertActivity.java,該類未包括在公開的API中 

2. com.android.internal.app.AlertController類, 位置- myeclair\frameworks\base\core\java\com\android\internal\app\AlertController.java,該類未包括在公開的API中 

 

6.ui.ConfirmRateLimitActivity ,發送多條彩信時向用戶提示確認的界面,它包括了自動 應答操作——即用戶 超過一段時間 未作出響應時自動取消發送。

 

7、.ui.ClassZeroActivity ,ClassZero是一種特殊的短消息類型,它會直接顯示在用戶屏幕上並等待用戶操作。ClassZeroActivity正是用來顯示此類型的短信消息 ,並運行用戶將信息保存起來 

ClassZeroActivity .java中有編譯錯誤,因爲它無法訪問以下類:

1. android.provider.Telephony 類,所在位置- myeclair\frameworks\base\core\java\android\provider\Telephony.java,該類被標記爲 @hide 

2. com.google.android.mms.util.SqliteWrapper: 位置- myeclair\frameworks\base\core\java\com\google\android\mms\ util\SqliteWrapper.java ,該類未包括在公開的API中。

 

8、.ui.MessagingPreferenceActivity ,這是Messaging應用的系統配置界面,其中有針對SMS、MMS、存儲限制等配置屬性,以及管理存儲在 SIM卡中 的短信消息。該Activity啓動時會檢查當前是否有SIM,以及是否支持MMS來動態調整配置項列表。

MessagingPreferenceActivity .java中有編譯錯誤,因爲它無法訪問TelephonyManager.getDefault()方法,可以考慮使用Context.getSystemService(Context.TELEPHONY_SERVICE)方法來得到類實例。

 

9、.ui.ManageSimMessages ,用於管理Sim卡中短消息的界面,它以列表的形式顯示了存儲在SIM卡中的短消息,並允許用戶將信息轉存到手機內存中,或者刪除消息。

ManageSimMessages .java中有編譯錯誤,因爲它無法訪問以下類:

1. android.provider.Telephony 類,所在位置- myeclair\frameworks\base\core\java\android\provider\Telephony.java,該類被標記爲 @hide 

2. com.google.android.mms.util.SqliteWrapper: 位置- myeclair\frameworks\base\core\java\com\google\android\mms\ util\SqliteWrapper.java ,該類未包括在公開的API中。

 

10、.ui.SearchActivity ,用於信息搜索的操作界面。Android通過系統服務Context. SEARCH_SERVICE(即SearchManager類)提供了強大的信息搜索功能。在該應用中通過對聯繫人(或者電話號碼)、主題等信息的匹配來搜索信息,並將結果顯示在一個列表中。

SearchActivity .java中有編譯錯誤,因爲它無法訪問以下類:

1. android.provider.Telephony 類,所在位置- myeclair\frameworks\base\core\java\android\provider\Telephony.java,該類被標記爲 @hide 

 

11、.ui.SlideshowEditActivity , 所謂Slide是指MM中的一頁內容 即一幀,通常被稱爲幻燈片。 SlideshowEditActivity是彩信中所有內容(即多個Slide)的列表,用戶可以選定列表項進入Slide播放/修改界面。

SlideshowEditActivity .java中有編譯錯誤,因爲它無法訪問以下類:

1. com.google.android.mms.*: 位置- myeclair\frameworks\base\core\java\com\google\android\mms\*,這些類未包括在公開的API中 

 

 

12、.ui.SlideshowActivity , 用於播放Slide幻燈片的界面,它會在全屏狀態下顯示幻燈片的內容。

SlideshowActivity .java中有編譯錯誤,因爲它無法訪問以下類:

1. com.google.android.mms.*: 位置- myeclair\frameworks\base\core\java\com\google\android\mms\*,這些類未包括在公開的API中 

 

13、.ui.SlideEditorActivity ,用於編輯Slide幻燈片內容的操作界面,它提供了:添加、移除 文本/圖片/音樂,以及Slide等功能。

SlideEditorActivity .java中有編譯錯誤,因爲它無法訪問以下類:

1. com.google.android.mms.*: 位置- myeclair\frameworks\base\core\java\com\google\android\mms\*,這些類未包括在公開的API中 

 

14、.ui.EditSlideDurationActivity ,用於修改Slide幻燈片持續顯示時間 的操作界面 ,默認持續顯示時間是5秒。

EditSlideDurationActivity .java編譯無錯誤。

 

Messaging中的Service

應用中共有兩個service:.transaction.TransactionService 和 .transaction.SmsReceiverService,前者負責處理與彩信(MMS)相關的網絡業務,後者是短消息(SMS)的接收器,兩者都會響應來自通訊網絡的通知並收取信息。它們只用於本應用內部(因爲其未聲明任何intent-filter),上文介紹的廣播接收器中有顯式啓動它們的代碼。以下我們將分別分析兩個Service的基本實現。

 

1、.transaction.SmsReceiverService ,它被創建時首先 初始化了新的工作線程(HandlerThread對象)用來在後臺完成相關動作,緊接着在onStartCommand方法裏會將具體的任務通過消息(即調用service的Intent)發送給工作線程進行處理。根據Intent.Action的名稱,工作線程會處理4中情況:

A.系統啓動完成後BOOT_COMPLETED:把發件箱(outbox)中的消息移動到發送隊列(QueuedBox),然後開始發送隊列中的消息,最後調用updateNewMessageIndicator方法更新狀態欄消息指示圖標;

B.處理Sms接收handleSmsReceived:從Intent中取得消息對象,直接顯示給用戶(Class0類型)或者保持到數據庫中。

C.處理Sms發送handleSmsSent:從待發送消息隊列中取得消息,並按次序逐個發送;

D.處理通訊網絡狀態改變handleServiceStateChanged:用戶從無信號狀態進入有信息號狀態後,繼續執行發送任務的情況;

 

2、.transaction.TransactionService  是處理與彩信相關業務的服務組件,根據代碼中的註釋可以瞭解到: 收發彩信時可以是移動數據網絡(mobile data network)或Wi-Fi網絡。當沒有可用的移動數據網絡連接時,會嘗試通過Wi-Fi網絡發送/接收MMS信息(如果有 Wi-Fi 網絡的話)。

 同樣在onCreate方法裏首先創建了後臺工作線程,通過NetworkConnectivityListener類( 一個被@hide的類 )監聽通訊網絡鏈接狀態的變化,並根據不同的鏈接狀態作出相應的反應。

緊接着就是onStartCommand方法了,它首先會檢測當前的網絡連接狀態,然後分別完成以下幾件事情:

A.針對收發彩信的業務,它將intent.getExtras()包裝成一個DTO—— TransactionBundle,再通過launchTransaction()方法將具體工作交給後臺工作線程去處理。

B.如果 intent.getExtras()爲Null時,它會嘗試從數據庫中掃描是否有(上次系統結束時)未完成的操作,如果有則遍歷所有操作項,逐個調用launchTransaction()方法,以完成操作;

 

 

重點還是在後臺工作線程的處理邏輯上,在代碼中表現爲handleMessage方法,它共處理以下幾種不同類型的業務消息:

 

Ⅰ.EVENT_CONTINUE_MMS_CONNECTIVITY ,與彩信系統建立網絡連接,它首 先會檢查當前是否有待處理的業務,然後通過調用beginMmsConnectivity方法來創建於彩信系統的網絡連接,如果網絡連接被正確建立,那麼它會通過一個30秒間隔的計時器來維持連接的持續存在;

 

Ⅱ.EVENT_DATA_STATE_CHANGED ,網絡連接狀態發生改變分支,這一分支是通過對NetworkConnectivityListener對象的監聽而獲得回調。在該分支中首先確認了網絡連接的有效性,(代碼在此處僅允許ConnectivityManager.TYPE_MOBILE_MMS類型那麼wi-fi連接屬於該類型? ),然後創建 TransactionSettings對象,並調用processPendingTransaction方法處理具體的彩信業務;

 

Ⅲ.EVENT_TRANSACTION_REQUEST ,這是對具體彩信業務的處理分支,它首 先創建了承載業務參數的TransactionSettings對象,該對象包含有彩信中心服務地址(mmscUrl)、代理服務器地址和端口等用於建立 網絡連接的參數,然後根據不同的業務類型,分別進行處理。當前僅明確處理了以下4中業務:

1、NOTIFICATION_TRANSACTION,通過一條Push數據,通知手機端收到有新信息;

2、RETRIEVE_TRANSACTION,收取彩信;

3、SEND_TRANSACTION,發送彩信;

4、READREC_TRANSACTION,彩信閱讀報告;

用於處理具體業務的關鍵代碼在processTransaction方法中,它首先檢查業務是否已存在於處理隊列中(mProcessing & mPending),然後調用beginMmsConnectivity()方法確認網絡連接有效性,並點亮終端屏幕,然後將業務對象條件到處理隊列中並向業務附加觀察者,最後調用業務自身process()方法完成網絡通信。注意:業務的process方法被調用又會觸發觀察者(即當前service) 的update方法被調用,這使得剛纔被處理掉的業務從隊列中被移除,並且開始處理下一條業務;


Ⅴ.EVENT_HANDLE_NEXT_PENDING_TRANSACTION ,這是一個多條彩信業務能夠  連續 處理的關鍵分支,首先在當前service中有mProcessing數組列表用於緩存連續的彩信業務,每條彩信業務是一個可被觀察的對象(注:觀察者模式 ), 當前service是唯一觀察者,其會感知到一條業務已處理結束,並觸發下一條業務處理的開始;

 

所有彩信業務處理完成後, 會調用 service中的endMmsConnectivity()方法,結束與彩信中心的網絡連接,並撤銷屏幕點亮。


轉載:http://www.cnblogs.com/lilactutu/archive/2010/12/03/1895720.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章