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

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                原文出處——>[ndroid應用程序內部啟動Activity過程(startActivity)的源代碼分析](http://blog.csdn.net/luoshengyang/article/details/6703247) 上文介紹了Android應用程序的啟動過程,即應用程序默認Activity的啟動過程,一般來說,這種默認Activity是在新的進程和任務中啟動的;本文將繼續分析在應用程序內部啟動非默認Activity的過程的源代碼,這種非默認Activity一般是在原來的進程和任務中啟動的。 這里,我們像上一篇文章Android應用程序啟動過程源代碼分析一樣,采用再上一篇文章Android應用程序的Activity啟動過程簡要介紹和學習計劃所舉的例子來分析在應用程序內部啟動非默認Activity的過程。 在應用程序內部啟動非默認Activity的過程與在應用程序啟動器Launcher中啟動另外一個應用程序的默認Activity的過程大體上一致的,因此,這里不會像上文Android應用程序啟動過程源代碼分析一樣詳細分析每一個步驟,我們著重關注有差別的地方。 回憶一下Android應用程序的Activity啟動過程簡要介紹和學習計劃一文所用的應用程序Activity,它包含兩個Activity,分別是MainActivity和SubActivity,前者是應用程序的默認Activity,后者是非默認Activity。MainActivity啟動起來,通過點擊它界面上的按鈕,便可以在應用程序內部啟動SubActivity。 我們先來看一下應用程序的配置文件AndroidManifest.xml,看看這兩個Activity是如何配置的: ~~~ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="shy.luo.activity" android:versionCode="1" android:versionName="1.0"> <application android:icon="@drawable/icon" android:label="@string/app_name"> <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> <activity android:name=".SubActivity" android:label="@string/sub_activity"> <intent-filter> <action android:name="shy.luo.activity.subactivity"/> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity> </application> </manifest> ~~~ 這里可以很清楚地看到,MainActivity被配置成了應用程序的默認Activity,而SubActivity可以通過名稱“shy.luo.activity.subactivity”隱式地啟動,我們來看一下src/shy/luo/activity/MainActivity.java文件的內容,可以清楚地看到SubActivity是如何隱式地啟動的: ~~~ public class MainActivity extends Activity implements OnClickListener { ...... @Override public void onClick(View v) { if(v.equals(startButton)) { Intent intent = new Intent("shy.luo.activity.subactivity"); startActivity(intent); } } } ~~~ 這里,首先創建一個名稱為“shy.luo.activity.subactivity”的Intent,然后以這個Intent為參數,通過調用startActivity函數來實現隱式地啟動SubActivity。 有了這些背景知識后,我們就來看一下SubActivity啟動過程的序列圖: ![](https://box.kancloud.cn/6735add9d5a24dd971ca8eae41befc85_673x768.gif) 與前面介紹的MainActivity啟動過程相比,這里少了中間創建新的進程的步驟;接下來,我們就詳細分析一下SubActivity與MainActivity啟動過程中有差別的地方,相同的地方請參考Android應用程序啟動過程源代碼分析一文。 * Step 1. Activity.startActivity 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 2大體一致,通過指定名稱“shy.luo.activity.subactivity”來告訴應用程序框架層,它要隱式地啟動SubActivity。所不同的是傳入的參數intent沒有Intent.FLAG_ACTIVITY_NEW_TASK標志,表示這個SubActivity和啟動它的MainActivity運行在同一個Task中。 * Step 2. Activity.startActivityForResult 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 3一致。 * Step 3. Instrumentation.execStartActivity 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 4一致。 * Step 4. ActivityManagerProxy.startActivity 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 5一致。 * Step 5. ActivityManagerService.startActivity 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 6一致。 * Step 6. ActivityStack.startActivityMayWait 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 7一致。 * Step 7. ActivityStack.startActivityLocked 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 8一致。 * Step 8. ActivityStack.startActivityUncheckedLocked 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 9有所不同,主要是當前要啟動的Activity與啟動它的Activity是在同一個Task中運行的,我們來詳細看一下。這個函數定義在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中: ~~~ public class ActivityStack { ...... final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, Uri[] grantedUriPermissions, int grantedMode, boolean onlyIfNeeded, boolean doResume) { final Intent intent = r.intent; final int callingUid = r.launchedFromUid; int launchFlags = intent.getFlags(); ...... if (sourceRecord == null) { ...... } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { ...... } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE ...... } if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { ...... } boolean addingToTask = false; if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { ...... } if (r.packageName != null) { // If the activity being launched is the same as the one currently // at the top, then we need to check if it should only be launched // once. ActivityRecord top = topRunningNonDelayedActivityLocked(notTop); if (top != null && r.resultTo == null) { if (top.realActivity.equals(r.realActivity)) { ...... } } } else { ...... } boolean newTask = false; // Should this be considered a new task? if (r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { ...... } else if (sourceRecord != null) { ...... // An existing activity is starting this new activity, so we want // to keep the new one in the same task as the one that is starting // it. r.task = sourceRecord.task; ...... } else { ...... } ...... startActivityLocked(r, newTask, doResume); return START_SUCCESS; } ...... } ~~~ 這里,參數intent的標志位Intent.FLAG_ACTIVITY_NEW_TASK沒有設置,在配置文件AndriodManifest.xml中,SubActivity也沒有配置啟動模式launchMode,于是它就默認標準模式,即ActivityInfo.LAUNCH_MULTIPLE,因此,下面if語句不會執行: ~~~ if (((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 && (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0) || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { ...... } ~~~ 于是,變量addingToTask為false。 繼續往下看: ~~~ if (r.packageName != null) { // If the activity being launched is the same as the one currently // at the top, then we need to check if it should only be launched // once. ActivityRecord top = topRunningNonDelayedActivityLocked(notTop); if (top != null && r.resultTo == null) { if (top.realActivity.equals(r.realActivity)) { ...... } } } ~~~ 這里看一下當前要啟動的Activity是否就是當前堆棧頂端的Activity,如果是的話,在某些情況下,就不用再重新啟動了。函數topRunningNonDelayedActivityLocked返回當前 堆棧頂端的Activity,這里即為MainActivity,而當前要啟動的Activity為SubActivity,因此,這二者不相等,于是跳過里面的if語句。 接著往下執行: ~~~ // Should this be considered a new task? if (r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { ...... } else if (sourceRecord != null) { ...... // An existing activity is starting this new activity, so we want // to keep the new one in the same task as the one that is starting // it. r.task = sourceRecord.task; ...... } else { ...... } ~~~ 前面說過參數intent的標志位Intent.FLAG_ACTIVITY_NEW_TASK沒有設置,而這里的sourceRecord即為當前執行啟動Activity操作的Activity,這里即為MainActivity,因此,它不為null,于是于MainActivity所屬的Task設置到r.task中去,這里的r即為SubActivity。看到這里,我們就知道SubActivity要和MainActivity運行在同一個Task中了,同時,變量newTask的值為false。 最后,函數進 入startActivityLocked(r, newTask, doResume)進一步處理了。這個函數同樣是定義在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中: ~~~ public class ActivityStack { ...... private final void startActivityLocked(ActivityRecord r, boolean newTask, boolean doResume) { final int NH = mHistory.size(); int addPos = -1; if (!newTask) { // If starting in an existing task, find where that is... boolean startIt = true; for (int i = NH-1; i >= 0; i--) { ActivityRecord p = (ActivityRecord)mHistory.get(i); if (p.finishing) { continue; } if (p.task == r.task) { // Here it is! Now, if this is not yet visible to the // user, then just add it without starting; it will // get started when the user navigates back to it. addPos = i+1; if (!startIt) { mHistory.add(addPos, r); r.inHistory = true; r.task.numActivities++; mService.mWindowManager.addAppToken(addPos, r, r.task.taskId, r.info.screenOrientation, r.fullscreen); if (VALIDATE_TOKENS) { mService.mWindowManager.validateAppTokens(mHistory); } return; } break; } if (p.fullscreen) { startIt = false; } } } ...... // Slot the activity into the history stack and proceed mHistory.add(addPos, r); r.inHistory = true; r.frontOfTask = newTask; r.task.numActivities++; ...... if (doResume) { resumeTopActivityLocked(null); } } ...... } ~~~ 這里傳進來的參數newTask為false,doResume為true。當newTask為false,表示即將要啟動的Activity是在原有的Task運行時,如果這個原有的Task當前對用戶不可見時,這時候就不需要繼續執行下去了,因為即使把這個Activity啟動起來,用戶也看不到,還不如先把它保存起來,等到下次這個Task對用戶可見的時候,再啟動不遲。這里,這個原有的Task,即運行MainActivity的Task當前對用戶是可見的,因此,會繼續往下執行。 接下去執行就會把這個SubActivity通過mHistroy.add(addPos, r)添加到堆棧頂端去,然后調用resumeTopActivityLocked進一步操作。 * ep 9. ActivityStack.resumeTopActivityLocked 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 10一致。 但是要注意的是,執行到這個函數的時候,當前處于堆棧頂端的Activity為SubActivity,ActivityStack的成員變量mResumedActivity指向MainActivity。 * Step 10. ActivityStack.startPausingLocked 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 11一致。 從這里開始,ActivityManagerService通知MainActivity進入Paused狀態。 * Step 11. ApplicationThreadProxy.schedulePauseActivity 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 12一致。 * Step 12. ApplicationThread.schedulePauseActivity 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 13一致。 * Step 13. ActivityThread.queueOrSendMessage 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 14一致。 * Step 14. H.handleMessage 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 15一致。 * Step 15. ActivityThread.handlePauseActivity 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 16一致。 * Step 16. ActivityManagerProxy.activityPaused 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 17一致。 * Step 17. ActivityManagerService.activityPaused 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 18一致。 * Step 18. ActivityStack.activityPaused 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 19一致。 * Step 19. ActivityStack.completePauseLocked 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 20一致。 執行到這里的時候,MainActivity就進入Paused狀態了,下面就開始要啟動SubActivity了。 * Step 20. ActivityStack.resumeTopActivityLokced 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 21一致。 * Sep 21. ActivityStack.startSpecificActivityLocked 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 22就有所不同了,這里,它不會調用mService.startProcessLocked來創建一個新的進程來啟動新的Activity,我們來看一下這個函數的實現,這個函數定義在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中: ~~~ public class ActivityStack { ...... private final void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { // Is this activity's application already running? ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid); ...... if (app != null && app.thread != null) { try { realStartActivityLocked(r, app, andResume, checkConfig); return; } catch (RemoteException e) { ...... } } ...... } ...... } ~~~ 這里由于不是第一次啟動應用程序的Activity(MainActivity是這個應用程序第一個啟動的Activity),所以下面語句: ~~~ ProcessRecord app = mService.getProcessRecordLocked(r.processName, nfo.applicationInfo.uid); ~~~ 取回來的app不為null。在上一篇文章Android應用程序啟動過程源代碼分析中,我們介紹過,在Activity應用程序中的AndroidManifest.xml配置文件中,我們沒有指定application標簽的process屬性,于是系統就會默認使用package的名稱,這里就是"shy.luo.activity"了。每一個應用程序都有自己的uid,因此,這里uid + process的組合就可以創建一個全局唯一的ProcessRecord。這個ProcessRecord是在前面啟動MainActivity時創建的,因此,這里將它取回來,并保存在變量app中。注意,我們也可以在AndroidManifest.xml配置文件中指定SubActivity的process屬性值,這樣SubActivity就可以在另外一個進程中啟動,不過很少有應用程序會這樣做,我們不考慮這種情況。 這個app的thread也是在前面啟動MainActivity時創建好的,于是,這里就直接調用realStartActivityLocked函數來啟動新的Activity了,新的Activity的相關信息都保存在參數r中了。 * Step 22. ActivityStack.realStartActivityLocked 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 28一致。 * Step 23. ApplicationThreadProxy.scheduleLaunchActivity 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 29一致。 * Step 24. ApplicationThread.scheduleLaunchActivity 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 30一致。 * Step 25. ActivityThread.queueOrSendMessage 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 31一致。 * Step 26. H.handleMessage 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 32一致。 * Step 27. ActivityThread.handleLaunchActivity 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 33一致。 * Step 28. ActivityThread.performLaunchActivity 這一步與上一篇文章Android應用程序啟動過程源代碼分析的Step 34一致,不過,這里要從ClassLoader里面加載的類就是shy.luo.activity.SubActivity了。 * Step 29. SubAcitiviy.onCreate 這個函數定義在packages/experimental/Activity/src/shy/luo/activity/SubActivity.java文件中,這是我們自定義的app工程文件: ~~~ public class SubActivity extends Activity implements OnClickListener { ...... @Override public void onCreate(Bundle savedInstanceState) { ...... Log.i(LOG_TAG, "Sub Activity Created."); } ...... } ~~~ 這樣,SubActivity就在應用程序Activity內部啟動起來了。 在應用程序內部啟動新的Activity的過程要執行很多步驟,但是整體來看,主要分為以下四個階段: * 一. Step 1 - Step 10:應用程序的MainActivity通過Binder進程間通信機制通知ActivityManagerService,它要啟動一個新的Activity; * 二. Step 11 - Step 15:ActivityManagerService通過Binder進程間通信機制通知MainActivity進入Paused狀態; * 三. Step 16 - Step 22:MainActivity通過Binder進程間通信機制通知ActivityManagerService,它已經準備就緒進入Paused狀態,于是ActivityManagerService就準備要在MainActivity所在的進程和任務中啟動新的Activity了; * 四. Step 23 - Step 29:ActivityManagerService通過Binder進程間通信機制通知MainActivity所在的ActivityThread,現在一切準備就緒,它可以真正執行Activity的啟動操作了。 和上一篇文章Android應用程序啟動過程源代碼分析中啟動應用程序的默認Activity相比,這里在應用程序內部啟動新的Activity的過程少了中間創建新的進程這一步,這是因為新的Activity是在已有的進程和任務中執行的,無須創建新的進程和任務。 這里同樣不少地方涉及到了Binder進程間通信機制,相關資料請參考Android進程間通信(IPC)機制Binder簡要介紹和學習計劃一文。 這里希望讀者能夠把本文和上文Android應用程序啟動過程源代碼分析仔細比較一下應用程序的默認Activity和非默認Activity啟動過程的不同之處,以加深對Activity的理解。 最后,在本文和上文中,我們多次提到了Android應用程序中任務(Task)的概念,它既不是我們在Linux系統中所理解的進程(Process),也不是線程(Thread),它是用戶為了完成某個目標而需要執行的一系列操作的過程的一種抽象。這是一個非常重要的概念,它從用戶體驗的角度出發,界定了應用程序的邊界,極大地方便了開發者利用現成的組件(Activity)來搭建自己的應用程序,就像搭積木一樣,而且,它還為應用程序屏蔽了底層的進程,即一個任務中的Activity可以都是運行在同一個進程中,也中可以運行在不同的進程中。Android應用程序中的任務的概念,具體可以參考官方文檔http://developer.android.com/guide/topics/fundamentals/tasks-and-back-stack.html ,上面已經介紹的非常清楚了。
                  <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>

                              哎呀哎呀视频在线观看