Android Mms之:深入理解Compose
Mms中的ComposeMessageActivity(以下簡(jiǎn)稱Composer)是整個(gè)Mms中最重要的一個(gè)組件,它負(fù)責(zé)編輯信息,發(fā)送信息,管理信息,接收信息,與外部應(yīng)用接口。在Mms內(nèi)部與Composer關(guān)聯(lián)的類和組件特別多,幾乎所有的類和組件都與Composer有關(guān)聯(lián),關(guān)于信息的所有操作流程都起始于Composer;在外部Composer也是公開的接口,能夠處理Intent.ACTION_SEND和Intent.ACTION_SENDTO以及文件類型為audio/*,image/*,video/*和text/*。
Composer是一個(gè)標(biāo)準(zhǔn)的Activity,它的啟動(dòng)流程也要經(jīng)過(guò)onCreate(), onStart(),onResume(),銷毀流程要經(jīng)過(guò)onPause(),onStop()和onDestroy() 。除此之外,其他的操作都要經(jīng)過(guò)用戶來(lái)觸發(fā),或者由其他事件,比如新來(lái)信息,數(shù)據(jù)庫(kù)變化等。
初始化流程
Composer的初始化流程要做的事情有初始化UI,注冊(cè)一些Receiver和Listener,初始化Conversation和WorkingMessage,查詢信息等。其中,初始始化Conversation和WorkingMessage是最重要的,因?yàn)閁I和一些操作要依賴于Conversation是否存在,以及消息數(shù)量和是否有草稿。所以這里我們主要討論初始化Conversation和WorkingMessage。
初始化的主要流程都是在initialize()函數(shù)中進(jìn)行的,這里也主要解析下initialize()函數(shù)。initialize()最先要做的就是初始化WorkingMessage,創(chuàng)建一個(gè)新的WorkingMessage對(duì)象mWorkingMessage;然后就是根據(jù)Intent和Bundle來(lái)初始化Conversation,這一過(guò)程相當(dāng)重要,因?yàn)镃onversation對(duì)象含有這一會(huì)話的所有重要數(shù)據(jù),包括是否有草稿,信息的數(shù)量,是新建的信息還是已有信息,這些信息都將影響后續(xù)的初始化工作。
initActivityState()主要看二個(gè)參數(shù)一個(gè)是所傳入的Bundle另一個(gè)就是Intent。它會(huì)優(yōu)先查看Bundle,如果Bundle對(duì)象不為空的話,會(huì)從Bundle之中取出一些狀態(tài),比如收信人recipients,比如退出狀態(tài)exit_on_sent等。根據(jù)所拿出來(lái)的的收信人就可以用Conversation的get()方法來(lái)獲取Conversation對(duì)象mConversation,之后便會(huì)讓mWorkingMessage從Bundle中讀取相關(guān)的數(shù)據(jù)。其實(shí),這里從Bundle中初始化是與onSaveInstanceState()相對(duì)應(yīng)的,在onSaveInstanceState()中會(huì)保存recipients和讓mWorkingMessage寫數(shù)據(jù)到Bundle中,以保存Activity的狀態(tài)??傮w來(lái)講,onSaveInstanceState是保存Activity的狀態(tài),而initActivityState()中當(dāng)Bundle不為空時(shí)是恢復(fù)Activity的狀態(tài)。
如果Bundle對(duì)象為空的話,那么就從Intent中來(lái)初始化相關(guān)的數(shù)據(jù),這也是大多數(shù)的情況所走的邏輯。首先是檢查Intent中是否有thread_id和address,也直接從Intent的Uri中搜尋收信人的相關(guān)信息,以便用Conversation.get()來(lái)獲取Conversation對(duì)象mConversation。之后還會(huì)試圖從Intent中獲取其他信息比如消息的主體sms_body,主題subject等。
調(diào)用完initActivityState()以后,mWorkingMessage和mConversation二個(gè)對(duì)象應(yīng)該都被正確的初始化了。這時(shí)候就要處理特殊的Intent:ACTION_SEND和Forward了。先是處理ACTION_SEND,這是對(duì)外的接口,當(dāng)外部程序想通過(guò)MMS來(lái)發(fā)送文本(text/*),圖片(image/*),音頻(audio/*)和視頻(video/*)時(shí)就會(huì)通過(guò)Intent.ACTION_SEND來(lái)發(fā)送。對(duì)于這個(gè)Intent的處理很簡(jiǎn)單就是把相關(guān)文件的Uri,通常放在intent.getExtras(Intent.EXTRA_STREAM)中,把Uri加載為附件,也可以通過(guò)Intent.SEND_MULTIPLE來(lái)處理多個(gè)附件,但是邏輯是一樣的。Forward是Intent當(dāng)中有forward_message時(shí),同時(shí)取出另外二個(gè)選項(xiàng),一個(gè)是要轉(zhuǎn)發(fā)的信息的Uri,一個(gè)是主題subject和消息主體sms_body。因?yàn)閷?duì)于SEND和Forward都僅指定信息的內(nèi)容而沒(méi)有指定收信人,所以mConversation對(duì)象是沒(méi)有實(shí)際內(nèi)容的,它們都會(huì)與新建信息是一樣的,只不過(guò)有信息的內(nèi)容。
除了ACTION_SEND和Forward的信息有內(nèi)容外,其他的信息都需要檢查是否有草稿,以便能加載草稿。加載草稿是由mWorkingMessage.loadDraft()來(lái)完成的,它會(huì)檢查mConversation的狀態(tài),如果有草稿存在就從數(shù)據(jù)庫(kù)中加載出來(lái)。
到此,初始化的關(guān)鍵操作都已完成,數(shù)據(jù)的加載都已完成,剩下的工作就是根據(jù)這些數(shù)據(jù)來(lái)初始化UI,比如是否顯示收信編輯欄等。
銷毀流程
Composer的銷毀要做的只有二件事,一個(gè)是保存當(dāng)前編輯的信息內(nèi)容,也就是保存草稿,如果有的話;另一個(gè)就是通過(guò)onSaveInstanceState來(lái)保存狀態(tài),不過(guò)這個(gè)通常用不到,只有當(dāng)Composer被系統(tǒng)殺掉并希望重啟時(shí)才會(huì)調(diào)用到。
保存草稿的工作主要放在onStop()的時(shí)候,所以每當(dāng)用戶離開Composer頁(yè)面都會(huì)走進(jìn)onStop()也就都會(huì)檢查相關(guān)的條件以確定是否要保存草稿。保存草稿的條件有三個(gè):信息有內(nèi)容(mWorkingMessage.isWorthSaving(),有內(nèi)容,有主題,有附件均可),并且信息有正確的收信人(在不在數(shù)據(jù)庫(kù)中均可),還有就是Composer在等待其他Activity(這個(gè)通常出現(xiàn)在添加聯(lián)系人或添加草稿過(guò)程中,因?yàn)橐D(zhuǎn)到其他Activity,所以Composer也會(huì)走到onStop(),但是這個(gè)時(shí)候因?yàn)樾畔⑦€在編輯中,所以就需要保存草稿)。如果以上條件不滿足就丟棄信息內(nèi)容(mWorkingMessage.discard()),否則就保存草稿(mWorkingMessage.saveDraft())。
對(duì)外公開的接口
跟Android中組件復(fù)用的公開接口一樣,Composer對(duì)外公開的接口也是通過(guò)處理Intent來(lái)完成的,主要是二個(gè)Intent一個(gè)是Intent.ACTION_SEND,另一個(gè)就是Intent.ACTION_SENDTO。接口的聲明處是在AndroidManifest文件中的IntentFilter。對(duì)于處理,有二個(gè)地方,一個(gè)是在initActivityState()中,會(huì)從Intent中嘗試取出address, sms_body 和subject;另外對(duì)于ACTION_SEND需要明顯的處理handleSendIntent(),因?yàn)樾枰獜腎ntent中取出信息的內(nèi)容通常都是多媒體文件,取出多媒體文件然后通過(guò)mWorkingMessage.setAttachment()添加為信息的附件。
還有一個(gè)接口就是對(duì)于分享聯(lián)系人,分享聯(lián)系人的方式是把聯(lián)系人的信息作為短信的內(nèi)容發(fā)送出去。這個(gè)過(guò)程實(shí)際上是由Contacts中的ShareContactsViaSMS來(lái)先行處理,它會(huì)把聯(lián)系人的信息從數(shù)據(jù)庫(kù)中讀取出來(lái),然后拼成一個(gè)字串再用Intent當(dāng)成sms_body傳給Mms發(fā)送。
與其他組件的交互
Composer在編輯信息過(guò)程中,特別是編輯MMS的過(guò)程中需要不斷的與其他組件進(jìn)行交互,比如添加圖片,添加音頻,添加視頻或拍攝圖片,拍攝視頻等。對(duì)于選擇圖片,選擇視頻來(lái)講是通過(guò)與Gallery應(yīng)用進(jìn)行交互,發(fā)送GET_CONTENT的Intent給Gallery,Gallery會(huì)列出圖片和視頻供用戶選擇,當(dāng)用戶選擇后,Gallery會(huì)把用戶所選擇的圖片或視頻的Uri傳給Composer,之后Composer就用傳過(guò)來(lái)的Uir進(jìn)行添加附件的動(dòng)作。對(duì)于音頻是與Music應(yīng)用進(jìn)行交互,邏輯類似。對(duì)于拍攝圖片和拍攝視頻和錄制音頻流程稍有不同。拍攝圖片和拍攝視頻在請(qǐng)求Intent中要指定輸出的路徑通過(guò)Intent.EXTRA_OUTPUT來(lái)指定輸出Uri。Camera在拍攝的過(guò)程中會(huì)把數(shù)據(jù)寫在所指定的Uri中,之后Composer會(huì)直接從這個(gè)Uri中讀取文件(這里與2.3不同,2.3是Camera把文件的Uri放在Intent中)。TempFileProvider就專門用于管理拍攝圖片和拍攝視頻時(shí)臨時(shí)存儲(chǔ)數(shù)據(jù)的。傳給Camera的Uri是”content://mms_temp_file/scrapSpace”,這個(gè)Uri由TempFileProvider來(lái)管理,由Camera來(lái)使用,當(dāng)Camera要寫數(shù)據(jù)時(shí)openFile()時(shí),TempFileProvider就會(huì)創(chuàng)建一個(gè)臨時(shí)文件,在外部存儲(chǔ)卡上/sdcard/Android/data/com.android.mms/mms_temp_file/scrapSpace/.temp.jpg,Camera所拍攝的圖片和視頻都存放在這個(gè)文件之中。TempFileProvider中還有方法以操作這個(gè)文件,比如TempFileProvider.renaceScrapFile()就是把.temp.jpg文件重命名成為一個(gè).3gp的視頻。除了Composer會(huì)用到這個(gè)TempFileProvider,在SlideEditorActivity中編輯一張幻燈片的時(shí)候也會(huì)用到這個(gè)臨時(shí)文件,因?yàn)榫庉嫽脽羝臅r(shí)候也是能夠通過(guò)Camera來(lái)添加圖片的視頻的。
- Android Compose自定義TextField實(shí)現(xiàn)自定義的輸入框
- Android Jetpack Compose實(shí)現(xiàn)列表吸頂效果
- Android Jetpack Compose無(wú)限加載列表
- Android之Compose頁(yè)面切換動(dòng)畫介紹
- Android Compose實(shí)現(xiàn)底部按鈕以及首頁(yè)內(nèi)容詳細(xì)過(guò)程
- Android Compose實(shí)現(xiàn)伸縮ToolBar的思路詳解
- Android?Jetpack庫(kù)剖析之ViewModel組件篇
- Android?Jetpack庫(kù)剖析之LiveData組件篇
- Android?Jetpack結(jié)構(gòu)運(yùn)用Compose實(shí)現(xiàn)微博長(zhǎng)按點(diǎn)贊彩虹效果
相關(guān)文章
Android開發(fā)歡迎頁(yè)點(diǎn)擊跳過(guò)倒計(jì)時(shí)進(jìn)入主頁(yè)
沒(méi)點(diǎn)擊跳過(guò)自然進(jìn)入主頁(yè),點(diǎn)擊跳過(guò)之后立即進(jìn)入主頁(yè),這個(gè)功能怎么實(shí)現(xiàn)呢,本文通過(guò)實(shí)例代碼給大家介紹Android開發(fā)歡迎頁(yè)點(diǎn)擊跳過(guò)倒計(jì)時(shí)進(jìn)入主頁(yè),感興趣的朋友一起看看吧2023-12-12Android仿新浪微博發(fā)送菜單界面的實(shí)現(xiàn)
這篇文章主要介紹了Android仿新浪微博發(fā)送菜單界面的實(shí)現(xiàn),幫助大家更好的理解和學(xué)習(xí)使用Android開發(fā),感興趣的朋友可以了解下2021-04-04Android應(yīng)用啟動(dòng)流程之從啟動(dòng)到可交互的過(guò)程解析
這篇文章將給大家總結(jié)學(xué)習(xí)Android 基礎(chǔ)知識(shí),Android應(yīng)用啟動(dòng)流程,從啟動(dòng)到可交互的過(guò)程解析,在學(xué)習(xí)過(guò)程中,大家最好是把源碼下載下來(lái),感興趣的小伙伴跟著小編一起來(lái)看看吧2023-08-08在啟動(dòng)欄制作android studio啟動(dòng)圖標(biāo)
這篇文章主要介紹了在啟動(dòng)欄制作android studio啟動(dòng)圖標(biāo)的相關(guān)知識(shí),需要的朋友可以參考下2018-03-03Android應(yīng)用UI開發(fā)中Fragment的常見(jiàn)用法小結(jié)
這篇文章主要介紹了Android應(yīng)用UI開發(fā)中Fragment的常見(jiàn)用法小結(jié),Fragment的存在是為了解決不同屏幕分辯率的動(dòng)態(tài)和靈活UI設(shè)計(jì),需要的朋友可以參考下2016-02-02Android中NavigationView的使用與相關(guān)問(wèn)題解決
大家都知道NavigationView的引入讓 Android側(cè)邊欄實(shí)現(xiàn)起來(lái)相當(dāng)方便,最近公司項(xiàng)目中也使用這個(gè)新的控件完成了側(cè)邊欄的改版。在使用過(guò)程中遇到一些問(wèn)題所以記錄一下。本文分為兩個(gè)部分,一是基本使用,二是相關(guān)問(wèn)題的解決,感興趣的朋友們下面來(lái)一起看看吧。2016-10-10淺談Android手機(jī)聯(lián)系人開發(fā)之增刪查改功能
這篇文章主要介紹了Android手機(jī)聯(lián)系人開發(fā)之增刪查改功能,需要的朋友可以參考下2017-05-05Android基于OpenCV實(shí)現(xiàn)圖像修復(fù)
實(shí)際應(yīng)用中,圖像常常容易受損,如存在污漬的鏡頭、舊照片的劃痕、人為的涂畫(比如馬賽克),亦或是圖像本身的損壞。修復(fù)圖像就成為一個(gè)常見(jiàn)的需求了,本文講述Android基于OpenCV實(shí)現(xiàn)圖像修復(fù)的步驟,有此需求的朋友可以參考下2021-06-06Android實(shí)現(xiàn)圖片點(diǎn)擊預(yù)覽效果(zoom動(dòng)畫)
本文主要介紹了Android實(shí)現(xiàn)圖片點(diǎn)擊預(yù)覽效果的方法步驟。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-03-03