<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                對于做App的開發人員而言,Activity是四大組件中用的最多的,也是最復雜的,我這里只講Activity的啟動和通信原理。還有一些相關的概念,比如說View、Looper、Intent、Resource,我以后另起章節來介紹。 > **注**:對四大組件的分析,都是基于羅升陽的那本分析Android底層的書,我把其中羅列的大部分代碼都刪掉了,只保留那些對App開發人員有用的一些代碼片段和一些關鍵類名,并融入了我對四大組件的理解。 1)首先要搞清,App是怎么啟動的。 在手機屏幕上點擊某個App的Icon,假設就是斗魚App吧,這個App的首頁(或引導頁)就出現在我們面前了。這個看似簡單的操作,背后經歷了Activity和AMS的反反復復的通信過程。 首先要搞清楚,在手機屏幕上點擊App的icon快捷圖標,此時手機屏幕就是一個Activity,而這個Activity所在的App,業界稱之為Launcher。Launcher是手機系統廠商提供的,類似小米華為這樣的手機,比拼的就是誰的Launcher絢麗和人性化。 Launcher這個App,其實和我們做的各類應用類App沒有什么不同,我們大家用過華為、小米之類的手機,預裝App以及我們下載的各種App,都顯示在Launcher上,每個App表現為一個Icon。Icon多了可以分頁,可以分組,此外,Launcher也會發起網絡請求,調用天氣的數據,顯示在屏幕上,所謂的人性化界面。 還記得我們在開發一款App時,在Manifest文件中是怎么定義默認啟動Activity的么?如下所示: ~~~ <activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> ~~~ 而Launcher中為每個App的icon提供了啟動這個App所需要的Intent信息,如下所示(比如說斗魚的包名是): * action:android.intent.action.MAIN * category: android.intent.category.LAUNCHER * cmp: 斗魚的包名+ 首頁Activity名 這些信息是App安裝(或Android系統啟動)的時候,PackageManagerService從斗魚的apk包的manifest文件中讀取到的。 所以點擊icon就啟動了斗魚App中的首頁。 2)啟動App哪有那么簡單 前面介紹的只是App啟動的一個最簡單的概述。 下面是根Activity的啟動過程 ![](https://box.kancloud.cn/51d2ff0baa74f1871a56ff5355931a9c_1501x2356.jpg) 仔細看,我們會發現,Launcher和斗魚是兩個不同的App,他們位于不同的進程中,它們之間的通信是通過Binder完成的——這時候AMS出場了。 仍然以啟動斗魚App為例子,整體流程是: * Launcher通知AMS,要啟動斗魚App,而且指定要啟動斗魚的哪個頁面(也就是首頁)。 * AMS通知Launcher,好了我知道了,沒你什么事了,同時,把要啟動的首頁記下來。 * Launcher當前頁面進入Paused狀態,然后通知AMS,我睡了,你可以去找斗魚App了。 * AMS檢查斗魚App是否已經啟動了。是,則喚起斗魚App即可。否,就要啟動一個新的進程。AMS在新進程中創建一個ActivityThread對象,啟動其中的main函數。 * 斗魚App啟動后,通知AMS,說我啟動好了。 * AMS翻出之前在第二步存的值,告訴斗魚App,啟動哪個頁面。 * 斗魚App啟動首頁,創建Context并與首頁Activity關聯。然后調用首頁Activity的onCreate函數。 至此啟動流程完成,分成兩部分,1-3步,Launcher和AMS相互通信,而后面幾步,斗魚App和AMS相互通信。 這會牽扯一堆類進來,列舉如下,在接下來的分析中,我們都會遇到: * Instrumentation * ActivityThread * H * LoadedApk * AMS * ActivityManagerNative和ActivityManagerProxy * ApplicationThread和ApplicationThreadProxy 第1階段 Launcher通知AMS ![](http://images2015.cnblogs.com/blog/13430/201705/13430-20170519224933760-1702392298.png) 這是我根據老羅那本書中對Activity的分析,自己手繪的UML圖,一共七張,也就是Activity啟動所經歷的七個階段。建議各位讀者也親自手繪一遍,從而就加深理解。 第1步、第2步 從上圖中我們看到,點擊Launcher上的斗魚App的icon快捷圖標,這時會調用Launcher的startActivitySafely方法,其實還是會調用Activity的startActivity方法,intent中帶著要啟動斗魚App所需要的關鍵信息,如下所示: ~~~ action = “android.intent.action.MAIN” category = “android.intent.category.LAUNCHER” cmp = “com.douyu.activity.MainActivity” ~~~ 第3行代碼是我猜的,就是斗魚App在Mainfest文件中指定為首頁的那個Activity。這樣,我們終于明白,為什么在Mainfest中,給首頁指定action和category了。在app的安裝過程中,會把這個信息“記錄”在Launcher的斗魚啟動快捷圖標中。關于App的安裝過程,我會在后面的文章詳細介紹。 startActivity這個方法,如果我們看它的實現,會發現它調來調去,經過一系列startActivity的重載方法,最后會走到startActivityForResult方法。 **Activity:startActivity** ~~~ @Override public void startActivity(Intent intent, @Nullable Bundle options) { if (options != null) { startActivityForResult(intent, -1, options); } else { // Note we want to go through this call for compatibility with // applications that may have overridden the method. startActivityForResult(intent, -1); } } ~~~ 我們知道startActivityForResult需要兩個參數,一個是intent,另一個是code,這里code是-1,表示Launcher才不關心斗魚的App是否啟動成功了呢。 第3步: startActivityForResult Activity內部會保持一個對Instrumentation的引用,但凡是做過App單元測試的同學,對這個類都很熟悉,稱之為儀表盤。 在startActivityForResult方法的實現中,會調用Instrumentation的execStartActivity方法。 **Activity:startActivityForResult** ~~~ public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) { if (mParent == null) { Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); ................. } else { // Note we want to go through this method for compatibility with // existing applications that may have overridden it. mParent.startActivityFromChild(this, intent, requestCode); } } } ~~~ 看到這里,我們發現有個mMainThread變量,這是一個ActivityThread類型的變量。 ActivityThread,就是主線程,也就是UI線程,它是在App啟動時創建的,它代表了App應用程序。 啥?ActivityThread代表了App應用程序,那Application類豈不是被架空了?其實,Application對我們App開發人員來說也許很重要,但是在Android系統中還真的沒那么重要,他就是個上下文。Activity不是有個Context上下文嗎?Application就是整個ActivityThread的上下文。 ActivityThread則沒有那么簡單了。它里面有main函數。 我們知道大部分程序都有main函數,比如java、C#,遠了不說,iPhone App用到的Objective-C,也有main函數,那么Android的main函數藏在哪里?就在ActivityThread中,如下所示,代碼太多,我只截取了一部分 **ActivityThread:main** ~~~ public static void main(String[] args) { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain"); SamplingProfilerIntegration.start(); // CloseGuard defaults to true and can be quite spammy. We // disable it here, but selectively enable it later (via // StrictMode) on debug builds, but using DropBox, not logs. CloseGuard.setEnabled(false); Environment.initForCurrentUser(); .......................................... } ~~~ 又有人會問?不是說誰寫的程序,誰就要提供main函數,作為入口嗎?但Android App卻不是這樣的。Android App的main函數,在ActivityThread里面,而這個類是Android系統提供的底層類,不是我們提供的。 所以這就是Andoid有趣的地方。Android App的入口是Mainifest中定義默認啟動Activity。這是由Android AMS與四大組件的通信機制決定的。 回到代碼來,這里要傳遞2個很重要的參數: * 通過ActivityThread的getApplicationThread方法取到一個Binder對象,它的類型為ApplicationThread,它代表著Launcher所在的App進程。 * mToken,這也是個Binder對象,它代表了Launcher這個Activity,這里也通過Instrumentation傳給AMS,AMS一查電話簿,就知道是誰向AMS發起請求了。 這兩個參數是伏筆,傳遞給AMS,以后AMS想反過來通知Launcher,就能通過這兩個參數,找到Launcher。 第4步,Instrumentation的execStartActivity方法 Instrumentation絕對是Adnroid測試團隊的最愛,因為它可以幫我們啟動Activity。 回到我們的App啟動過程來,在Instrumentation的execStartActivity方法中, **Instrumentation:execStartActivity** ~~~ public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { .................................................... try { .................................... int result = ActivityManagerNative.getDefault() .startActivity(whoThread, who.getBasePackageName(), intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } return null; } ~~~ 我理解這就是一個透傳,Activity把數據借助Instrumentation,傳遞給ActivityManagerNative,沒太多有趣的內容,就不多講了。 第5步:AMN的getDefault方法 ActivityManagerNative,簡稱AMN。這個類后面會反復用到。 AMN通過getDefault方法,從ServiceManager中取得一個名為activity的對象,然后把它包裝成一個ActivityManagerProxy對象(簡稱AMP),AMP就是AMS的代理對象。 > **注意**: > 1. ServiceManager是一個容器類。 > 2. AMN的getDefault方法返回類型為IActivityManager,而不是AMP。IActivityManager是一個實現了IInterface的接口,里面定義了四大組件所有的生命周期。 AMN和AMP都實現了IActivityManager接口,AMS繼承自AMN(好亂),那么對照著前面AIDL的UML,就不難理解了: ![](http://images2015.cnblogs.com/blog/13430/201705/13430-20170519225130822-867987839.png) 第6步,AMP的startActivity方法 看到這里,你會發現AMP的startActivity方法,和AIDL的Proxy方法,是一模一樣的,寫入數據到另一個進程,也就是AMS,然后等待AMS返回結果。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看