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。