MMS入口分析:
在Mms中最重要的兩個Activity,一個是conversationList(簡訊列表) ,另一個就是ComposeMessageActivity(單個對話或者簡訊)。每個ComposeMessageActivity錄屬於一個conversation或者不屬於任何conversation(無收件者草稿);每個converation由獨立的threadId來相互區分。每個converation有一個唯一WorkingMessage表示這個在thread(話題)下。ConversationList和ComposeMessageActivity的launch mode都是singleTop。
Android的launch mode涉及到Task和Activity,使用者看到的每個介面,基本上都是一個個的Activity,而這些Activity以棧的形式放入在Task中,比如進棧操作由使用者的點擊進入其他Activity產生,出棧由使用者按下back鍵完成。一個Task的屬性,由他擁有的第一個Activity,也就是棧底的那個activity決定。一個Activity的launch mode,就是決定他在Task中的表現特點:
1.standard模式,就是沒有特點,可以在一個Task裡隨便加,隨便加幾個執行個體都成,還能同時在多個Task中共存。
2.singleTask是整個手機中只能有一個,而且必須出現在這個Task的棧底。
3.singleInstance表示這個Acitivity獨佔了整個Task,這個task只有這麼一個Activity。
4.singleTop和standard有點類似,區別是,他會去重用Task頂層的他自己的實體。比如說ABC是3個Activity,mode是standard,在一個棧中的排列是A-B-C,這時候由C再new一個C的intent時,Task變成A-B-C-C; 如果C的mode湊巧是singleTop,那麼頂部只能是一個C,也就是在A-B-C這個情境下,再來一個C時,Task變成A-B-C。只是現在頂部的C已經是嶄新的C,不是原來那個。
另外launcher按下一個C的表徵圖,這時候,系統會檢索所有以C為棧底的Task,如果找到了,就把他起起來,如果沒有,就起一個新的。
ComposeMessageActivity中幾個重要的函數:
1.onSaveInstanceState函數的調用,同onPause()以及onStop()有區別,但是能保證如果ComposeMessageActivity被殺死時,他能在onStop()前被調用。這個函數調用發生在ComposeMessageActivity異常終止時,儲存部分現場資訊,這些資訊可以恢複使用者離開時的情境。
workingMessage初始化時如果之前ComposeMessageActivity在onSaveInstanceState時儲存了部分資訊,則會從舊有連絡人裡面讀取出來,連絡人相互之間用“;”分割開。workingmessage也由之前儲存的變數初始化,這個初始化就基本完成了,返回了。
如果沒有儲存,則從傳入的intent中讀取thread_id值,進而得到初始化需要的資訊:
A. thread_id>0 ; 那麼mConversation從Conversation的cache中,由thread_id取得。
B. thread_id<=0;那麼從intent的Date獲得thread_id,再得不到就說明之前沒有過這個thread了,可能使用者是手寫的地址,就從address去產生一個ContactList,從ContactList去Conversation的Cache裡匹配得到相應的Conversation。
這時候,如果匹配還是沒有得到Conversation時,Cache裡就會偷偷產生一個Conversation返回回來,適用於你這個狀況。Cache用來保證連絡人匹配的所有訊息,被放入同一個對話(thread)中。再如果連絡人也是空的,那麼直接產生一個新的Conversation; 這個Conversation是廉價的,因為他沒有thread_id,不被放入cache,在使用ensurethreadid之前,他可以建立無數個,可以隨意調用建立出來。
有了conversation之後,就可以initMessageList,查詢顯示出這個thread下面的所有訊息
2.handleSendIntent()函數用來判斷是否由一個intent調用起來ComposeMessageActivity,特徵是intent可以得到Action和mimeType; 比如ACTION_SEND和ACTION_SEND_MULTIPLE; 檔案流比如EXTRA_STREAM,字串EXTRA_TEXT;遇到這些情況,直接添加附件,其他流程類似於messagelist繼續。
3. handleForwardedMessage()函數,在不是intent調用的ComposeMessageActivity時,檢查是不是由轉寄發起的調用,這些檢查歸根到底是檢查intent的extra中帶的關鍵字,比如 “forwarded_message” , intent.getAction() ,“recipients” , “thread_id”
4.ComposeMessageActivity的入口只有兩個:onCreate()和 onNewIntent(),這兩個初始化函數的核心是: initialize(Bundle savedInstanceState)
onCreate()比較簡單,他的內容主要是:初始設定變數 、初始化UI 、initialize()。
onNewIntent() 只發生在,singleTop的情境,也就是說,已經有一個ComposeMessageActivity在Task的頂部(也就是使用者的視線內,或者被隱藏到後台了),之後在從launcher的簡訊或者從statusbar的簡訊入口進入時,就會調用到onNewIntent。在onNewIntent調用時,需要儲存原有的ComposeMessageActivity的狀態,並用新的Intent裡的資訊,形成新的ComposeMessageActivity,從而替代他。原有的Intent的資訊在mConversation和mWorkingMessage裡面,比如mConversation.getThreadId() 得到threadId,如果threadId是0,則說明原來的ComposeMessageActivity包含一個草稿,需要儲存。比如mWorkingMessage裡面,包含最新的收件者資訊,需要用mWorkingMessage.syncWorkingRecipients()複製到conversation中,這時候把這份連絡人複製到Conversation裡,以備儲存草稿用。關於新起來的這個Intent和原來的ComposeMessageActivity是不是屬於同一個conversation的判斷;判斷的唯一依據是連絡人清單。新來的intent的uri調用uri.getSchemeSpecificPart()函數返回的是一個由“;“分割的電話號碼序列,可以拼裝成ContactList,是新來的連絡人清單。通過對比,可以知道原來的和新來的兩者之間的ContactList是否相同;如果對比是不同的,那麼新的intent將佔據ComposeMessageActivity,如果對比相同,則不用更換Conversation就佔據這個操作。這個佔據包括三步:
1、saveDraft() 函數 ,儲存原有conversation的草稿 ,(mRecipientsContainer同步到workingmessage中去。)
2,initialize()函數 ,也即(I)裡提到的流程,只是傳入的初始化參數是null,也就是說在init時,沒有在bundle裡提供連絡人
3,loadMessageContent()函數,查詢Conversation下的訊息狀況,初始化連絡人資訊,畫相關按鈕介面
onCreate()入口:
1、建立簡訊;bundle和intent都為空白初始化
2、在conversation點擊一條簡訊: intent非空,由intent初始化
3、轉寄:handleForwardedMessage時把intent中的uri中的資料取出來放入mWorkingMessage,有文本以及可能的多媒體訊息;同時把list的cursor置空。
4 檔案或者文字通過簡訊發送
handleSendIntent()處理,如果intent中有extra內容,可以附帶Intent.EXTRA_STREAM或者Intent.EXTRA_TEXT;前者就是一個檔案流,可以解析出來多媒體檔案,後者是一個文本。還有一種是Intent.ACTION_SEND_MULTIPLE。