<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>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                startActivityAndWait函數有很多參數,先來認識一下它們。 **ActiivtyManagerService.java::startActivityAndWait原型** ~~~ publicfinal WaitResult startActivityAndWait( /* 在絕大多數情況下,一個Acitivity的啟動是由一個應用進程發起的,IApplicationThread是 應用進程和AMS交互的通道,也可算是調用進程的標示,在本例中,AM并非一個應用進程,所以 傳遞的caller為null */ IApplicationThread caller, //Intent及resolvedType,在本例中,resolvedType為null Intentintent, String resolvedType, //下面兩個參數和授權有關,讀者可參考第3章對CopyboardService分析中介紹的授權知識 Uri[] grantedUriPermissions,//在本例中為null intgrantedMode,//在本例中為0 IBinder resultTo,//在本例中為null,用于接收startActivityForResult的結果 StringresultWho,//在本例中為null //在本例中為0,該值的具體意義由調用者解釋。如果該值大于等于0,則AMS內部保存該值, //并通過onActivityResult返回給調用者 int requestCode, boolean onlyIfNeeded,//本例為false boolean debug,//是否調試目標進程 //下面3個參數和性能統計有關 StringprofileFile, ParcelFileDescriptor profileFd, booleanautoStopProfiler) ~~~ 關于以上代碼中一些參數的具體作用,以后碰到時會再作分析。建議讀者先閱讀SDK文檔中關于Activity類定義的幾個函數,如startActivity、startActivityForResult及onActivityResult等。 startActivityAndWait的代碼如下: **ActivityManagerService.java::startActivityAndWait** ~~~ publicfinal WaitResult startActivityAndWait(IApplicationThread caller, Intent intent, String resolvedType, Uri[]grantedUriPermissions, int grantedMode, IBinder resultTo,StringresultWho, int requestCode, booleanonlyIfNeeded, boolean debug,String profileFile, ParcelFileDescriptor profileFd, booleanautoStopProfiler) { //創建WaitResult對象用于存儲處理結果 WaitResult res = new WaitResult(); //mMainStack為ActivityStack類型,調用它的startActivityMayWait函數 mMainStack.startActivityMayWait(caller, -1, intent, resolvedType, grantedUriPermissions, grantedMode, resultTo, resultWho, requestCode, onlyIfNeeded, debug, profileFile, profileFd, autoStopProfiler, res, null);//最后一個參數為Configuration, //在本例中為null returnres; } ~~~ mMainStack為AMS的成員變量,類型為ActivityStack,該類是Activity調度的核心角色。正式分析它之前,有必要先介紹一下相關的基礎知識。 1. Task、Back Stack、ActivityStack及Launch mode (1) 關于Task及Back Stack的介紹 先來看圖6-10。 :-: ![](http://img.blog.csdn.net/20150803122911609?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖6-10 用戶想干什么 圖6-10列出了用戶在Android系統上想干的三件事情,分別用A、B、C表示,將每一件事情稱為一個Task。一個Task還可細分為多個子步驟,即Activity。 * * * * * **提示**:為什么叫Activity?讀者可參考Merrian-Webster詞典對Activity的解釋[^①]:“an organizational unit forperforming a specific function”,也就是說,它是一個有組織的單元,用于完成某項指定功能。 * * * * * 由圖6-10可知,A、B兩個Task使用了不同的Activity來完成相應的任務。注意,A、B這兩個Task的Activity之間沒有復用。 再來看C這個Task,它可細分為4個Activity,其中有兩個Activity分別使用了A Task的A1、B Task的B2。C Task為什么不新建自己的Activity,反而要用其他Task的呢?這是因為用戶想做的事情(即Task)可以完全不同,但是當細分Task為Activity時,就可能出現Activity功能類似的情況。既然A1、B2已能滿足要求,為何還要重復“發明輪子”呢?另外,通過重用Activity,也可為用戶提供一致的界面和體驗。 了解Android設計理念后,我們來看看Android是如何組織Task及它所包含的Activity的。此處有一個簡單的例子,如圖6-11所示。 :-: ![](http://img.blog.csdn.net/20150803122942720?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖6-11 Task及Back Stack示例 由圖6-11可知: - 本例中的Task包含4個Activity。用戶可單擊按鈕跳轉到下一個Activity。同時,通過返回鍵可回到上一個Activity。 - 虛線下方是這些Activity的組織方式。Android采用了Stack的方法管理這3個Activity。例如在A1啟動A2后,A2入棧成為棧頂成員,A1成為棧底成員,而界面顯示的是棧頂成員的內容。當按返回鍵時,A3出棧,這時候A2成為棧頂,界面顯示也相應變成了A2。 以上是一個Task的情況。那么,多個Task又會是何種情況呢?如圖6-12所示。 :-: ![](http://img.blog.csdn.net/20150803123111793?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖6-12 多個Task的情況 由圖6-12可知:對多Task的情況來說,系統只支持一個處于前臺的Task,即用戶當前看到的Activity所屬的Task,其余的Task均處于后臺,這些后臺Task內部的Activity保持順序不變。用戶可以一次將整個Task挪到后臺或者置為前臺。 * * * * * **提示**:用過Android手機的讀者應該知道,長按Home鍵,系統會彈出近期Task列表,使用戶能快速在多個Task間切換。 * * * * * 以上內容從抽象角度介紹了什么是Task,以及Android如何分解Task和管理Activity,那么在實際代碼中,是如何考慮并設計的呢? (2) 關于ActivityStack的介紹 通過上述分析,我們對Android的設計有了一定了解,那么如何用代碼來實現這一設計呢?此處有兩點需要考慮: - Task內部Activity的組織方式。由圖6-11可知,Android通過先入后出的方式來組織Activity。數據結構中的Stack即以這種方式工作。 - 多個Task的組織及管理方式。 Android設計了一個ActivityStack類來負責上述工作,它的組成如圖6-13所示。 :-: ![](http://img.blog.csdn.net/20150803123156782?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center) 圖6-13 ActivityStack及相關成員 由圖6-13可知: - Activity由ActivityRecord表示,Task由TaskRecord表示。ActivityRecord的task成員指向該Activity所在的Task。state變量用于表示該Activity所處的狀態(包括INITIALIZING、RESUMED、PAUSED等狀態)。 - ActivityStack用mHistory這個ArrayList保存ActivityRecord。令人大跌眼鏡的是,該mHistory保存了系統中所有Task的ActivityRecord,而不是針對某個Task進行保存。 - ActivityStack的mMainStack成員比較有意思,它代表此ActivityStack是否為主ActivityStack。有主必然有從,但是目前系統中只有一個ActivityStack,并且它的mMainStack為true。從ActivityStack的命名可推測,Android在開發之初也想用ActivityStack來管理單個Task中的ActivityRecord(在ActivityStack.java的注釋中說過,該類為“State and management of asingle stack of activities”),但不知何故,在現在的代碼實現將所有Task的ActivityRecord都放到mHistory中了,并且依然保留mMainStack。 - ActivityStack中沒有成員用于保存TaskRecord。 由上述內容可知,ActivityStack采用數組的方式保存所有Task的ActivityRecord,并且沒有成員保存TaskRecord。這種實現方式有優點亦有缺點: - 優點是少了TaskRecord一級的管理,直接以ActivityRecord為管理單元。這種做法能降低管理方面的開銷。 - 缺點是弱化了Task的概念,結構不夠清晰。 下面來看ActivityStack中幾個常用的搜索ActivityRecord的函數,代碼如下: **ActivityStack.java::topRunningActivityLocked** ~~~ /* topRunningActivityLocked: 找到棧中第一個與notTop不同的,并且不處于finishing狀態的ActivityRecord。當notTop為 null時,該函數即返回棧中第一個需要顯示的ActivityRecord。提醒讀者,棧的出入口只能是棧頂。 雖然mHistory是一個數組,但是查找均從數組末端開始,所以其行為也粗略符合Stack的定義 */ final ActivityRecordtopRunningActivityLocked(ActivityRecord notTop) { int i =mHistory.size()-1; while (i>= 0) { ActivityRecord r = mHistory.get(i); if (!r.finishing && r != notTop) return r; i--; } returnnull; } ~~~ 類似的函數還有: **ActivityStack.java::topRunningNonDelayedActivityLocked** ~~~ /* topRunningNonDelayedActivityLocked 與topRunningActivityLocked類似,但ActivityRecord要求增加一項,即delayeResume為 false */ final ActivityRecordtopRunningNonDelayedActivityLocked(ActivityRecord notTop) { int i =mHistory.size()-1; while(i >= 0) { ActivityRecord r = mHistory.get(i); //delayedResume變量控制是否暫緩resume Activity if (!r.finishing && !r.delayedResume&& r != notTop) return r; i--; } returnnull; } ~~~ ActivityStack還提供findActivityLocked函數以根據Intent及ActivityInfo來查找匹配的ActivityRecord,同樣,查找也是從mHistory尾端開始,相關代碼如下: **ActivityStack.java::findActivityLocked** ~~~ private ActivityRecord findActivityLocked(Intentintent, ActivityInfo info) { ComponentName cls = intent.getComponent(); if(info.targetActivity != null) cls= new ComponentName(info.packageName, info.targetActivity); final intN = mHistory.size(); for (inti=(N-1); i>=0; i--) { ActivityRecord r = mHistory.get(i); if (!r.finishing) if (r.intent.getComponent().equals(cls))return r; } return null; } ~~~ 另一個findTaskLocked函數的返回值是ActivityRecord,其代碼如下: **ActivityStack.java::findTaskLocked** ~~~ private ActivityRecord findTaskLocked(Intentintent, ActivityInfo info) { ComponentName cls = intent.getComponent(); if(info.targetActivity != null) cls= new ComponentName(info.packageName, info.targetActivity); TaskRecord cp = null; final intN = mHistory.size(); for (inti=(N-1); i>=0; i--) { ActivityRecord r = mHistory.get(i); //r.task!=cp,表示不搜索屬于同一個Task的ActivityRecord if(!r.finishing && r.task != cp && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) { cp = r.task; //如果Task的affinity相同,則返回這條ActivityRecord if(r.task.affinity != null) { if(r.task.affinity.equals(info.taskAffinity)) return r; }else if (r.task.intent != null &&r.task.intent.getComponent().equals(cls)) { //如果Task Intent的ComponentName相同 return r; }else if (r.task.affinityIntent != null &&r.task.affinityIntent.getComponent().equals(cls)) { //Task affinityIntent考慮 return r; }//if (r.task.affinity != null)判斷結束 }//if(!r.finishing && r.task != cp......)判斷結束 }//for循環結束 returnnull; } ~~~ 其實,findTaskLocked是根據mHistory中ActivityRecord所屬的Task的情況來進行相應的查找工作。 以上這4個函數均是ActivityStack中常用的函數,如果不需要逐項(case by case)地研究AMS,那么讀者僅需了解這幾個函數的作用即可。 (3) 關于Launch Mode的介紹 Launch Mode用于描述Activity的啟動模式,目前一共有4種模式,分別是standard、singleTop、singleTask和singleInstance。初看它們,較難理解,實際上不過是Android玩的一個“小把戲“而已。啟動模式就是用于控制Activity和Task關系的。 - standard:一個Task中可以有多個相同類型的Activity。注意,此處是相同類型的Activity,而不是同一個Activity對象。例如在Task中有A、B、C、D4個Activity,如果再啟動A類Activity, Task就會變成A、B、C、D、A。最后一個A和第一個A是同一類型,卻并非同一對象。另外,多個Task中也可以有同類型的Activity。 - singleTop:當某Task中有A、B、C、D4個Activity時,如果D想再啟動一個D類型的Activity,那么Task將是什么樣子呢?在singleTop模式下,Task中仍然是A、B、C、D,只不過D的onNewIntent函數將被調用以處理這個新Intent,而在standard模式下,則Task將變成A、B、C、D、D,最后的D為新創建的D類型Activity對象。在singleTop這種模式下,只有目標Acitivity當前正好在棧頂時才有效,例如只有處于棧頂的D啟動時才有用,如果D啟動不處于棧頂的A、B、C等,則無效。 - singleTask:在這種啟動模式下,該Activity只存在一個實例,并且將和一個Task綁定。當需要此Activity時,系統會以onNewIntent方式啟動它,而不會新建Task和Activity。注意,該Activity雖只有一個實例,但是在Task中除了它之外,還可以有其他的Activity。 - singleInstance:它是singleTask的加強版,即一個Task只能有這么一個設置了singleInstance的Activity,不能再有別的Activity。而在singleTask模式中,Task還可以有其他的Activity。 * * * * * **注意**,Android建議一般的應用開發者不要輕易使用最后兩種啟動模式。因為這些模式雖然名意上為Launch Mode,但是它們也會影響Activity出棧的順序,導致用戶按返回鍵返回時導致不一致的用戶體驗。 * * * * * 除了啟動模式外,Android還有其他一些標志用于控制Activity及Task之間的關系。這里只列舉一二,詳細信息請參閱SDK文檔中Intent的相關說明。 - FLAG_ACTIVITY_NEW_TASK:將目標Activity放到一個新的Task中。 - FLAG_ACTIVITY_CLEAR_TASK:當啟動一個Activity時,先把和目標Activity有關聯的Task“干掉“,然后啟動一個新的Task,并把目標Activity放到新的Task中。該標志必須和FLAG_ACTIVITY_NEW_TASK標志一起使用。 - FLAG_ACTIVITY_CLEAR_TOP:當啟動一個不處于棧頂的Activity時候,先把排在它前面的Activity“干掉”。例如Task有A、B、C、D4個Activity,要要啟動B,直接把C、D“干掉”,而不是新建一個B。 * * * * * **提示**:這些啟動模式和標志,在筆者看來很像洗撲克牌時的手法,因此可以稱之為小把戲。雖是小把戲,但是相關代碼的邏輯及分支卻異常繁雜,我們應從更高的角度來看待它們。 * * * * * 介紹完上面的知識后,下面來分析ActivityStack的startActivityMayWait函數。 2. ActivityStack的startActivityMayWait函數分析 startActivityMayWait函數的目標是啟動com.dfp.test.TestActivity,假設系統之前沒有啟動過該Activity,本例最終的結果將是: - 由于在am中設置了FLAG_ACTIVITY_NEW_TASK標志,因此除了會創建一個新的ActivityRecord外,還會新創建一個TaskRecord。 - 還需要啟動一個新的應用進程以加載并運行com.dfp.test.TestActivity的一個實例。 - 如果TestActivity不是Home,還需要停止當前正在顯示的Activity。 好了,將這個函數分三部分進行介紹,先來分析第一部分。 (1) startActivityMayWait分析之一 **ActivityStack.java::startActivityMayWait** ~~~ final int startActivityMayWait(IApplicationThreadcaller, int callingUid, Intentintent, String resolvedType, Uri[] grantedUriPermissions, intgrantedMode, IBinder resultTo, StringresultWho, int requestCode, boolean onlyIfNeeded, booleandebug, String profileFile, ParcelFileDescriptor profileFd, booleanautoStopProfiler, WaitResult outResult, Configuration config) { ...... //在本例中,已經指明了Component,這樣可省去為Intent匹配搜索之苦 booleancomponentSpecified = intent.getComponent() != null; //創建一個新的Intent,防止客戶傳入的Intent被修改 intent =new Intent(intent); //查詢滿足條件的ActivityInfo,在resolveActivity內部和PKMS交互,讀者不妨自己 //嘗試分析該函數 ActivityInfoaInfo = resolveActivity(intent, resolvedType, debug, profileFile, profileFd,autoStopProfiler); synchronized(mService) { int callingPid; if (callingUid >= 0) { callingPid= -1; } else if (caller == null) {//本例中,caller為null callingPid= Binder.getCallingPid();//取出調用進程的Pid //取出調用進程的Uid。在本例中,調用進程是am,它由shell啟動 callingUid= Binder.getCallingUid(); } else { callingPid= callingUid = -1; }// if (callingUid >= 0)判斷結束 //在本例中config為null mConfigWillChange= config != null && mService.mConfiguration.diff(config) != 0; finallong origId = Binder.clearCallingIdentity(); if (mMainStack && aInfo != null&& (aInfo.applicationInfo.flags& ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0){ /* AndroidManifest.xml中的Application標簽可以聲明一個cantSaveState 屬性,設置了該屬性的Application將不享受系統提供的狀態保存/恢復功能。 當一個Application退到后臺時,系統會為它保存狀態,當調度其到前臺運行時, 將恢復它之前的狀態,以保證用戶體驗的連續性。聲明了該屬性的Application被稱為 “heavy weight process”。可惜系統目前不支持該屬性,因為PackageParser 將不解析該屬性。詳情請見PackageParser.java parseApplication函數 */ } ......//待續 ~~~ startActivityMayWait第一階段的工作內容相對較簡單: - 首先需要通過PKMS查找匹配該Intent的ActivityInfo。 - 處理FLAG_CANT_SAVE_STATE的情況,但系統目前不支持此情況。 - 另外,獲取調用者的pid和uid。由于本例的caller為null,故所得到的pid和uid均為am所在進程的uid和pid。 下面介紹startActivityMayWait第二階段的工作。 (2) startActivityMayWait分析之二 **ActivityStack.java::startActivityMayWait** ~~~ //調用此函數啟動Activity,將返回值保存到res int res = startActivityLocked(caller, intent,resolvedType, grantedUriPermissions, grantedMode, aInfo, resultTo, resultWho, requestCode, callingPid, callingUid, onlyIfNeeded, componentSpecified, null); //如果configuration發生變化,則調用AMS的updateConfigurationLocked //進行處理。關于這部分內容,讀者學完本章后可自行分析 if(mConfigWillChange && mMainStack) { mService.enforceCallingPermission( android.Manifest.permission.CHANGE_CONFIGURATION, "updateConfiguration()"); mConfigWillChange= false; mService.updateConfigurationLocked(config,null, false); } ~~~ 此處,啟動Activity的核心函數是startActivityLocked,該函數異常復雜,將用一節專門分析。下面先繼續分析startActivityMayWait第三階段的工作。 (3) startActivityMayWait分析之三 **ActivityStack.java::startActivityMayWait** ~~~ if(outResult != null) { outResult.result = res;//設置啟動結果 if(res == IActivityManager.START_SUCCESS) { //將該結果加到mWaitingActivityLaunched中保存 mWaitingActivityLaunched.add(outResult); do { try { mService.wait();//等待啟動結果 } } while (!outResult.timeout && outResult.who == null); }else if (res == IActivityManager.START_TASK_TO_FRONT) { ......//處理START_TASK_TO_FRONT結果,讀者可自行分析 } }//if(outResult!= null)結束 return res; } } ~~~ 第三階段的工作就是根據返回值做一些處理,那么res返回成功(即res== IActivityManager.START_SUCCESS的時候)后為何還需要等待呢? 這是因為目標Activity要運行在一個新的應用進程中,就必須等待那個應用進程正常啟動并處理相關請求。注意,只有am設置了-W選項,才會進入wait這一狀態。 [^①]:http://www.merriam-webster.com/dictionary/activity中第六條解釋。
                  <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>

                              哎呀哎呀视频在线观看