天天看點

【凱子哥帶你學Framework】Activity啟動過程全解析 前言 學習目标 寫作方式 主要對象功能介紹 主要流程介紹 送給你們的彩蛋 參考文章 結語

it’s right time to learn android’s framework !

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#%e5%89%8d%e8%a8%80">前言</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#%e5%ad%a6%e4%b9%a0%e7%9b%ae%e6%a0%87">學習目标</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#%e5%86%99%e4%bd%9c%e6%96%b9%e5%bc%8f">寫作方式</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#%e4%b8%bb%e8%a6%81%e5%af%b9%e8%b1%a1%e5%8a%9f%e8%83%bd%e4%bb%8b%e7%bb%8d">主要對象功能介紹</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#%e4%b8%bb%e8%a6%81%e6%b5%81%e7%a8%8b%e4%bb%8b%e7%bb%8d">主要流程介紹</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#zygote%e6%98%af%e4%bb%80%e4%b9%88%e6%9c%89%e4%bb%80%e4%b9%88%e4%bd%9c%e7%94%a8">zygote是什麼有什麼作用</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#systemserver%e6%98%af%e4%bb%80%e4%b9%88%e6%9c%89%e4%bb%80%e4%b9%88%e4%bd%9c%e7%94%a8%e5%ae%83%e4%b8%8ezygote%e7%9a%84%e5%85%b3%e7%b3%bb%e6%98%af%e4%bb%80%e4%b9%88">systemserver是什麼有什麼作用它與zygote的關系是什麼</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#activitymanagerservice%e6%98%af%e4%bb%80%e4%b9%88%e4%bb%80%e4%b9%88%e6%97%b6%e5%80%99%e5%88%9d%e5%a7%8b%e5%8c%96%e7%9a%84%e6%9c%89%e4%bb%80%e4%b9%88%e4%bd%9c%e7%94%a8">activitymanagerservice是什麼什麼時候初始化的有什麼作用</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#launcher%e6%98%af%e4%bb%80%e4%b9%88%e4%bb%80%e4%b9%88%e6%97%b6%e5%80%99%e5%90%af%e5%8a%a8%e7%9a%84">launcher是什麼什麼時候啟動的</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#instrumentation%e6%98%af%e4%bb%80%e4%b9%88%e5%92%8cactivitythread%e6%98%af%e4%bb%80%e4%b9%88%e5%85%b3%e7%b3%bb">instrumentation是什麼和activitythread是什麼關系</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#%e5%a6%82%e4%bd%95%e7%90%86%e8%a7%a3ams%e5%92%8cactivitythread%e4%b9%8b%e9%97%b4%e7%9a%84binder%e9%80%9a%e4%bf%a1">如何了解ams和activitythread之間的binder通信</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#ams%e6%8e%a5%e6%94%b6%e5%88%b0%e5%ae%a2%e6%88%b7%e7%ab%af%e7%9a%84%e8%af%b7%e6%b1%82%e4%b9%8b%e5%90%8e%e4%bc%9a%e5%a6%82%e4%bd%95%e5%bc%80%e5%90%af%e4%b8%80%e4%b8%aaactivity">ams接收到用戶端的請求之後會如何開啟一個activity</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#%e9%80%81%e7%bb%99%e4%bd%a0%e4%bb%ac%e7%9a%84%e5%bd%a9%e8%9b%8b">送給你們的彩蛋</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#%e4%b8%8d%e8%a6%81%e4%bd%bf%e7%94%a8-startactivityforresultintentresultok">不要使用 startactivityforresultintentresult_ok</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#%e4%b8%80%e4%b8%aaapp%e7%9a%84%e7%a8%8b%e5%ba%8f%e5%85%a5%e5%8f%a3%e5%88%b0%e5%ba%95%e6%98%af%e4%bb%80%e4%b9%88">一個app的程式入口到底是什麼</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#%e6%95%b4%e4%b8%aaapp%e7%9a%84%e4%b8%bb%e7%ba%bf%e7%a8%8b%e7%9a%84%e6%b6%88%e6%81%af%e5%be%aa%e7%8e%af%e6%98%af%e5%9c%a8%e5%93%aa%e9%87%8c%e5%88%9b%e5%bb%ba%e7%9a%84">整個app的主線程的消息循環是在哪裡建立的</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#application%e6%98%af%e5%9c%a8%e4%bb%80%e4%b9%88%e6%97%b6%e5%80%99%e5%88%9b%e5%bb%ba%e7%9a%84oncreate%e4%bb%80%e4%b9%88%e6%97%b6%e5%80%99%e8%b0%83%e7%94%a8%e7%9a%84">application是在什麼時候建立的oncreate什麼時候調用的</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#%e5%8f%82%e8%80%83%e6%96%87%e7%ab%a0">參考文章</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#binder">binder</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#zygote">zygote</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#activitythreadinstrumentationams">activitythreadinstrumentationams</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#launcher">launcher</a>

<a target="_blank" href="http://blog.csdn.net/zhaokaiqiang1992/article/details/49428287#%e7%bb%93%e8%af%ad">結語</a>

一個app是怎麼啟動起來的?

app的程式入口到底是哪裡?

launcher到底是什麼神奇的東西?

聽說還有個ams的東西,它是做什麼的?

binder是什麼?他是如何進行ipc通信的?

activity生命周期到底是什麼時候調用的?被誰調用的?

等等…

你是不是還有很多類似的疑問一直沒有解決?沒關系,這篇文章将結合源碼以及大量的優秀文章,站在巨人的肩膀上,更加通俗的來試着解釋一些問題。但是畢竟源碼繁多、經驗有限,文中不免會出現一些纰漏甚至是錯誤,還懇請大家指出,互相學習。

了解從手機開機第一個zygote程序建立,到點選桌面上的圖示,進入一個app的完整流程,并且從源碼的角度了解到一個activity的生命周期是怎麼回事

了解到activitymanagerservices(即ams)、activitystack、activitythread、instrumentation等android framework中非常重要的基礎類的作用,及互相間的關系

了解ams與activitythread之間利用binder進行ipc通信的過程,了解ams和activitythread在控制activity生命周期起到的作用和互相之間的配合

了解與activity相關的framework層的其他瑣碎問題

這篇文章我決定采用一問一答的方式進行。

其實在這之前,我試過把每個流程的代碼調用過程,用粘貼源代碼的方式寫在文章裡,但是寫完一部分之後,發現由于代碼量太大,整篇文章和老太太的裹腳布一樣——又臭又長,雖然每個重要的操作可以顯示出詳細調用過程,但是太關注于細節反而導緻從整體上不能很好的把握。是以在原來的基礎之上進行了修改,對關鍵的幾個步驟進行重點介紹,力求語言簡潔,重點突出,進而讓大家在更高的層次上對framework層有個認識,然後結合後面我給出的參考資料,大家就可以更加快速,更加高效的了解這一塊的整體架構。

我們下面的文章将圍繞着這幾個類進行介紹。可能你第一次看的時候,印象不深,不過沒關系,當你跟随者我讀完這篇文章的時候,我會在最後再次列出這些對象的功能,相信那時候你會對這些類更加的熟悉和深刻。

activitymanagerservices,簡稱ams,服務端對象,負責系統中所有activity的生命周期

activitythread,app的真正入口。當開啟app之後,會調用main()開始運作,開啟消息循環隊列,這就是傳說中的ui線程或者叫主線程。與activitymanagerservices配合,一起完成activity的管理工作

applicationthread,用來實作activitymanagerservice與activitythread之間的互動。在activitymanagerservice需要管理相關application中的activity的生命周期時,通過applicationthread的代理對象與activitythread通訊。

applicationthreadproxy,是applicationthread在伺服器端的代理,負責和用戶端的applicationthread通訊。ams就是通過該代理與activitythread進行通信的。

instrumentation,每一個應用程式隻有一個instrumentation對象,每個activity内都有一個對該對象的引用。instrumentation可以了解為應用程序的管家,activitythread要建立或暫停某個activity時,都需要通過instrumentation來進行具體的操作。

activitystack,activity在ams的棧管理,用來記錄已經啟動的activity的先後關系,狀态資訊等。通過activitystack決定是否需要啟動新的程序。

activityrecord,activitystack的管理對象,每個activity在ams對應一個activityrecord,來記錄activity的狀态以及其他的管理資訊。其實就是伺服器端的activity對象的映像。

taskrecord,ams抽象出來的一個“任務”的概念,是記錄activityrecord的棧,一個“task”包含若幹個activityrecord。ams用taskrecord確定activity啟動和退出的順序。如果你清楚activity的4種launchmode,那麼對這個概念應該不陌生。

下面将按照app啟動過程的先後順序,一問一答,來解釋一些事情。

讓我們開始吧!

首先,你覺得這個單詞眼熟不?當你的程式crash的時候,列印的紅色log下面通常帶有這一個單詞。

zygote意為“受精卵“。android是基于linux系統的,而在linux中,所有的程序都是由init程序直接或者是間接fork出來的,zygote程序也不例外。

在android系統裡面,zygote是一個程序的名字。android是基于linux system的,當你的手機開機的時候,linux的核心加載完成之後就會啟動一個叫“init“的程序。在linux system裡面,所有的程序都是由init程序fork出來的,我們的zygote程序也不例外。

我們都知道,每一個app其實都是

一個單獨的dalvik虛拟機

一個單獨的程序

是以當系統裡面的第一個zygote程序運作之後,在這之後再開啟app,就相當于開啟一個新的程序。而為了實作資源共用和更快的啟動速度,android系統開啟新程序的方式,是通過fork第一個zygote程序實作的。是以說,除了第一個zygote程序,其他應用所在的程序都是zygote的子程序,這下你明白為什麼這個程序叫“受精卵”了吧?因為就像是一個受精卵一樣,它能快速的分裂,并且産生遺傳物質一樣的細胞!

首先我要告訴你的是,systemserver也是一個程序,而且是由zygote程序fork出來的。

知道了systemserver的本質,我們對它就不算太陌生了,這個程序是android framework裡面兩大非常重要的程序之一——另外一個程序就是上面的zygote程序。

為什麼說systemserver非常重要呢?因為系統裡面重要的服務都是在這個程序裡面開啟的,比如 

activitymanagerservice、packagemanagerservice、windowmanagerservice等等,看着是不是都挺眼熟的?

那麼這些系統服務是怎麼開啟起來的呢?

在zygote開啟的時候,會調用zygoteinit.main()進行初始化

我們看下startsystemserver()做了些什麼

activitymanagerservice,簡稱ams,服務端對象,負責系統中所有activity的生命周期。

activitymanagerservice進行初始化的時機很明确,就是在systemserver程序開啟的時候,就會初始化activitymanagerservice。從下面的代碼中可以看到

經過上面這些步驟,我們的activitymanagerservice對象已經建立好了,并且完成了成員變量初始化。而且在這之前,調用createsystemcontext()建立系統上下文的時候,也已經完成了msystemcontext和activitythread的建立。注意,這是系統程序開啟時的流程,在這之後,會開啟系統的launcher程式,完成系統界面的加載與顯示。

你是否會好奇,我為什麼說ams是服務端對象?下面我給你介紹下android系統裡面的伺服器和用戶端的概念。

其實伺服器用戶端的概念不僅僅存在于web開發中,在android的架構設計中,使用的也是這一種模式。伺服器端指的就是所有app共用的系統服務,比如我們這裡提到的activitymanagerservice,和前面提到的packagemanagerservice、windowmanagerservice等等,這些基礎的系統服務是被所有的app公用的,當某個app想實作某個操作的時候,要告訴這些系統服務,比如你想打開一個app,那麼我們知道了包名和mainactivity類名之後就可以打開

但是,我們的app通過調用startactivity()并不能直接打開另外一個app,這個方法會通過一系列的調用,最後還是告訴ams說:“我要打開這個app,我知道他的住址和名字,你幫我打開吧!”是以是ams來通知zygote程序來fork一個新程序,來開啟我們的目标app的。這就像是浏覽器想要打開一個超連結一樣,浏覽器把網頁位址發送給伺服器,然後還是伺服器把需要的資源檔案發送給用戶端的。

知道了android framework的用戶端伺服器架構之後,我們還需要了解一件事情,那就是我們的app和ams(systemserver程序)還有zygote程序分屬于三個獨立的程序,他們之間如何通信呢?

app與ams通過binder進行ipc通信,ams(systemserver程序)與zygote通過socket進行ipc通信。

那麼ams有什麼用呢?在前面我們知道了,如果想打開一個app的話,需要ams去通知zygote程序,除此之外,其實所有的activity的開啟、暫停、關閉都需要ams來控制,是以我們說,ams負責系統中所有activity的生命周期。

在android系統中,任何一個activity的啟動都是由ams和應用程式程序(主要是activitythread)互相配合來完成的。ams服務統一排程系統中所有程序的activity啟動,而每個activity的啟動過程則由其所屬的程序具體來完成。

這樣說你可能還是覺得比較抽象,沒關系,下面有一部分是專門來介紹ams與activitythread如何一起合作控制activity的生命周期的。

當我們點選手機桌面上的圖示的時候,app就由launcher開始啟動了。但是,你有沒有思考過launcher到底是一個什麼東西?

launcher本質上也是一個應用程式,和我們的app一樣,也是繼承自activity

packages/apps/launcher2/src/com/android/launcher2/launcher.java

launcher實作了點選、長按等回調接口,來接收使用者的輸入。既然是普通的app,那麼我們的開發經驗在這裡就仍然适用,比如,我們點選圖示的時候,是怎麼開啟的應用呢?如果讓你,你怎麼做這個功能呢?捕捉圖示點選事件,然後startactivity()發送對應的intent請求呗!是的,launcher也是這麼做的,就是這麼easy!

那麼到底是處理的哪個對象的點選事件呢?既然launcher是app,并且有界面,那麼肯定有布局檔案呀,是的,我找到了布局檔案launcher.xml

為了友善檢視,我删除了很多代碼,從上面這些我們應該可以看出一些東西來:launcher大量使用标簽來實作界面的複用,而且定義了很多的自定義控件實作界面效果,dock_divider從布局的參數聲明上可以猜出,是底部操作欄和上面圖示布局的分割線,而paged_view_indicator則是頁面訓示器,和app首次進入的引導頁下面的界面引導是一樣的道理。當然,我們最關心的是workspace這個布局,因為注釋裡面說在這裡面包含了5個螢幕的單元格,想必你也猜到了,這個就是在首頁存放我們圖示的那五個界面(不同的rom會做不同的diy,數量不固定)。

接下來,我們應該打開workspace_screen布局,看看裡面有什麼東東。

workspace_screen.xml

裡面就一個celllayout,也是一個自定義布局,那麼我們就可以猜到了,既然可以存放圖示,那麼這個自定義的布局很有可能是繼承自viewgroup或者是其子類,實際上,celllayout确實是繼承自viewgroup。在celllayout裡面,隻放了一個子view,那就是shortcutandwidgetcontainer。從名字也可以看出來,shortcutandwidgetcontainer這個類就是用來存放快捷圖示和widget小部件的,那麼裡面放的是什麼對象呢?

在桌面上的圖示,使用的是bubbletextview對象,這個對象在textview的基礎之上,添加了一些特效,比如你長按移動圖示的時候,圖示位置會出現一個背景(不同版本的效果不同),是以我們找到bubbletextview對象的點選事件,就可以找到launcher如何開啟一個app了。

除了在桌面上有圖示之外,在程式清單中點選圖示,也可以開啟對應的程式。這裡的圖示使用的不是bubbletextview對象,而是pagedviewicon對象,我們如果找到它的點選事件,就也可以找到launcher如何開啟一個app。

其實說這麼多,和今天的主題隔着十萬八千裡,上面這些東西,你有興趣就看,沒興趣就直接跳過,不知道不影響這篇文章閱讀。

bubbletextview的點選事件在哪裡呢?我來告訴你:在launcher.onclick(view v)裡面。

從上面的代碼我們可以看到,在桌面上點選快捷圖示的時候,會調用

那麼從程式清單界面,點選圖示的時候會發生什麼呢?實際上,程式清單界面使用的是appscustomizepagedview對象,是以我在這個類裡面找到了onclick(view v)。

com.android.launcher2.appscustomizepagedview.java

可以看到,調用的是

和上面一樣!這叫什麼?這叫殊途同歸!

是以咱們現在又明白了一件事情:不管從哪裡點選圖示,調用的都是launcher.startactivitysafely()。

下面我們就可以一步步的來看一下launcher.startactivitysafely()到底做了什麼事情。

調用了startactivity(v, intent, tag)

這裡會調用activity.startactivity(intent, opts.tobundle()),這個方法熟悉嗎?這就是我們經常用到的activity.startactivity(intent)的重載函數。而且由于設定了

是以這個activity會添加到一個新的task棧中,而且,startactivity()調用的其實是startactivityforresult()這個方法。

是以我們現在明确了,launcher中開啟一個app,其實和我們在activity中直接startactivity()基本一樣,都是調用了activity.startactivityforresult()。

還記得前面說過的instrumentation對象嗎?每個activity都持有instrumentation對象的一個引用,但是整個程序隻會存在一個instrumentation對象。當startactivityforresult()調用之後,實際上還是調用了minstrumentation.execstartactivity()

下面是minstrumentation.execstartactivity()的實作

是以當我們在程式中調用startactivity()的 時候,實際上調用的是instrumentation的相關的方法。

instrumentation意為“儀器”,我們先看一下這個類裡面包含哪些方法吧

【凱子哥帶你學Framework】Activity啟動過程全解析 前言 學習目标 寫作方式 主要對象功能介紹 主要流程介紹 送給你們的彩蛋 參考文章 結語

我們可以看到,這個類裡面的方法大多數和application和activity有關,是的,這個類就是完成對application和activity初始化和生命周期的工具類。比如說,我單獨挑一個callactivityoncreate()讓你看看

對activity.performcreate(icicle);這一行代碼熟悉嗎?這一行裡面就調用了傳說中的activity的入口函數oncreate(),不信?接着往下看

activity.performcreate()

沒騙你吧,oncreate在這裡調用了吧。但是有一件事情必須說清楚,那就是這個instrumentation類這麼重要,為啥我在開發的過程中,沒有發現他的蹤迹呢?

是的,instrumentation這個類很重要,對activity生命周期方法的調用根本就離不開他,他可以說是一個大管家,但是,這個大管家比較害羞,是一個女的,管内不管外,是老闆娘~

那麼你可能要問了,老闆是誰呀? 

老闆當然是大名鼎鼎的activitythread了!

activitythread你都沒聽說過?那你肯定聽說過傳說中的ui線程吧?是的,這就是ui線程。我們前面說過,app和ams是通過binder傳遞資訊的,那麼activitythread就是專門與ams的外交工作的。

ams說:“activitythread,你給我暫停一個activity!” 

activitythread就說:“沒問題!”然後轉身和instrumentation說:“老婆,ams讓暫停一個activity,我這裡忙着呢,你快去幫我把這事辦了把~” 

于是,instrumentation就去把事兒搞定了。

是以說,ams是董事會,負責指揮和排程的,activitythread是老闆,雖然說家裡的事自己說了算,但是需要聽從ams的指揮,而instrumentation則是老闆娘,負責家裡的大事小事,但是一般不抛頭露面,聽一家之主activitythread的安排。

前面我們說到,在調用startactivity()的時候,實際上調用的是

但是到這裡還沒完呢!裡面又調用了下面的方法

這裡的activitymanagernative.getdefault傳回的就是activitymanagerservice的遠端接口,即activitymanagerproxy。

怎麼知道的呢?往下看

再看activitymanagerproxy.startactivity(),在這裡面做的事情就是ipc通信,利用binder對象,調用transact(),把所有需要的參數封裝成parcel對象,向ams發送資料進行通信。

binder本質上隻是一種底層通信方式,和具體服務沒有關系。為了提供具體服務,server必須提供一套接口函數以便client通過遠端通路使用各種服務。這時通常采用proxy設計模式:将接口函數定義在一個抽象類中,server和client都會以該抽象類為基類實作所有接口函數,所不同的是server端是真正的功能實作,而client端是對這些函數遠端調用請求的包裝。

為了更友善的說明用戶端和伺服器之間的binder通信,下面以activitymanagerservices和他在用戶端的代理類activitymanagerproxy為例。

activitymanagerservices和activitymanagerproxy都實作了同一個接口——iactivitymanager。

雖然都實作了同一個接口,但是代理對象activitymanagerproxy并不會對這些方法進行真正地實作,activitymanagerproxy隻是通過這種方式對方法的參數進行打包(因為都實作了相同接口,是以可以保證同一個方法有相同的參數,即對要傳輸給伺服器的資料進行打包),真正實作的是activitymanagerservice。

但是這個地方并不是直接由用戶端傳遞給伺服器,而是通過binder驅動進行中轉。其實我對binder驅動并不熟悉,我們就把他當做一個中轉站就ok,用戶端調用activitymanagerproxy接口裡面的方法,把資料傳送給binder驅動,然後binder驅動就會把這些東西轉發給伺服器的activitymanagerservices,由activitymanagerservices去真正的實施具體的操作。

但是binder隻能傳遞資料,并不知道是要調用activitymanagerservices的哪個方法,是以在資料中會添加方法的唯一辨別碼,比如前面的startactivity()方法:

上面的start_activity_transaction就是方法标示,data是要傳輸給binder驅動的資料,reply則接受操作的傳回值。

用戶端:activitymanagerproxy =====&gt;binder驅動=====&gt; activitymanagerservice:伺服器

而且由于繼承了同樣的公共接口類,activitymanagerproxy提供了與activitymanagerservice一樣的函數原型,使使用者感覺不出server是運作在本地還是遠端,進而可以更加友善的調用這些重要的系統服務。

但是!這裡binder通信是單方向的,即從activitymanagerproxy指向activitymanagerservice的,如果ams想要通知activitythread做一些事情,應該咋辦呢?

還是通過binder通信,不過是換了另外一對,換成了applicationthread和applicationthreadproxy。

用戶端:applicationthread &lt;=====binder驅動&lt;===== applicationthreadproxy:伺服器

他們也都實作了相同的接口iapplicationthread

剩下的就不必多說了吧,和前面一樣。

ok,至此,點選桌面圖示調用startactivity(),終于把資料和要開啟activity的請求發送到了ams了。說了這麼多,其實這些都在一瞬間完成了,下面咱們研究下ams到底做了什麼。

注:前方有高能的方法調用鍊,如果你現在累了,請先喝杯咖啡或者是上趟廁所休息下

ams收到startactivity的請求之後,會按照如下的方法鍊進行調用

調用startactivity()

調用startactivityasuser()

在這裡又出現了一個新對象activitystacksupervisor,通過這個類可以實作對activitystack的部分操作。

繼續調用startactivitylocked()

調用startactivityuncheckedlocked(),此時要啟動的activity已經通過檢驗,被認為是一個正當的啟動請求。

終于,在這裡調用到了activitystack的startactivitylocked(activityrecord r, boolean newtask,boolean doresume, boolean keepcurtransition, bundle options)。

activityrecord代表的就是要開啟的activity對象,裡面分裝了很多資訊,比如所在的activitytask等,如果這是首次打開應用,那麼這個activity會被放到activitytask的棧頂,

調用的是activitystack.startactivitylocked()

靠!這來回折騰什麼呢!從activitystacksupervisor到activitystack,又調回activitystacksupervisor,這到底是在折騰什麼玩意啊!!!

淡定…淡定…我知道你也在心裡罵娘,世界如此美妙,你卻如此暴躁,這樣不好,不好…

來來來,咱們繼續哈,剛才說到哪裡了?哦,對,咱們一起看下stacksupervisor.resumetopactivitieslocked(this, r, options)

我…已無力吐槽了,又調回activitystack去了…

activitystack.resumetopactivitylocked()

咱們堅持住,看一下activitystack.resumetopactivityinnerlocked()到底進行了什麼操作

在這個方法裡,prev.app為記錄啟動lancher程序的processrecord,prev.app.thread為lancher程序的遠端調用接口iapplicationthead,是以可以調用prev.app.thread.schedulepauseactivity,到lancher程序暫停指定activity。

在lancher程序中消息傳遞,調用activitythread.handlepauseactivity(),最終調用activitythread.performpauseactivity()暫停指定activity。接着通過前面所說的binder通信,通知ams已經完成暫停的操作。

上面這些調用過程非常複雜,源碼中各種條件判斷讓人眼花缭亂,是以說如果你沒記住也沒關系,你隻要記住這個流程,了解了android在控制activity生命周期時是如何操作,以及是通過哪幾個關鍵的類進行操作的就可以了,以後遇到相關的問題之道從哪塊下手即可,這些過程我雖然也是撸了一遍,但還是記不清。

最後來一張高清無碼大圖,友善大家記憶:

<a target="_blank" href="http://i11.tietuku.com/0582844414810f38.png">請戳這裡(圖檔3.3m,請用電腦觀看)</a>

這是因為startactivity()是這樣實作的

是以

你不可能從onactivityresult()裡面收到任何回調。而這個問題是相當難以被發現的,就是因為這個坑,我工作一年多來第一次加班到9點 (ˇˍˇ)

是activitythread.main()。

是在activitythread初始化的時候,就已經建立消息循環了,是以在主線程裡面建立handler不需要指定looper,而如果在其他線程使用handler,則需要單獨使用looper.prepare()和looper.loop()建立消息循環。

也是在activitythread.main()的時候,再具體點呢,就是在thread.attach(false)的時候。

看你的表情,不信是吧!凱子哥帶你溜溜~

我們先看一下activitythread.attach()

這裡需要關注的就是mgr.attachapplication(mappthread),這個就會通過binder調用到ams裡面對應的方法

然後就是

thread是iapplicationthread,實際上就是applicationthread在服務端的代理類applicationthreadproxy,然後又通過ipc就會調用到applicationthread的對應方法

我們需要關注的其實就是最後的sendmessage(),裡面有函數的編号h.bind_application,然後這個messge會被h這個handler處理

最後就在下面這個方法中,完成了執行個體化,撥那個企鵝通過minstrumentation.callapplicationoncreate實作了oncreate()的調用。

data.info是一個loadeapk對象。 

loadeapk.data.info.makeapplication()

是以最後還是通過instrumentation.makeapplication()執行個體化的,這個老闆娘真的很厲害呀!

而且通過反射拿到application對象之後,直接調用attach(),是以attach()調用是在oncreate()之前的。

下面的這些文章都是這方面比較精品的,希望你抽出時間研究,這可能需要花費很長時間,但是如果你想進階為中進階開發者,這一步是必須的。

再次感謝下面這些文章的作者的分享精神。

<a target="_blank" href="http://blog.csdn.net/universus/article/details/6211589">android bander設計與實作 - 設計篇</a>

<a target="_blank" href="http://blog.csdn.net/luoshengyang/article/details/6768304">android系統程序zygote啟動過程的源代碼分析</a>

<a target="_blank" href="http://blog.csdn.net/xieqibao/article/details/6581975">android 之 zygote 與程序建立</a>

<a target="_blank" href="http://www.th7.cn/program/android/201404/187670.shtml">zygote淺談</a>

<a target="_blank" href="http://blog.csdn.net/myarrow/article/details/14224273">android activity.startactivity流程簡介</a>

<a target="_blank" href="http://blog.csdn.net/luoshengyang/article/details/6747696#comments">android應用程式程序啟動過程的源代碼分析</a>

<a target="_blank" href="http://laokaddk.blog.51cto.com/368606/1206840">架構層了解activity生命周期(app啟動過程)</a>

<a target="_blank" href="http://blog.csdn.net/yangwen123/article/details/35987609">android應用程式視窗設計架構介紹</a>

<a target="_blank" href="http://www.xuebuyuan.com/2172927.html">activitymanagerservice分析一:ams的啟動</a>

<a target="_blank" href="http://mobile.51cto.com/hot-312129.htm">android 4.0 launcher源碼分析系列(一)</a>

<a target="_blank" href="http://www.cnblogs.com/mythou/p/3187881.html">android launcher分析和修改9——launcher啟動app流程</a>

ok,到這裡,這篇文章算是告一段落了,我們再回頭看看一開始的幾個問題,你還困惑嗎?

再回過頭來看看這些類,你還迷惑嗎?

如果你還感到迷惑的話,就把這篇文章多讀幾遍吧,資訊量可能比較多,需要慢慢消化~