【Android源码 栏目提醒】:网学会员为需要Android源码 的朋友们搜集整理了Android应用程序内部启动Activity过程(startActivity)的源代码分析 - 企业软件开发相关资料,希望对各位网友有所帮助!
Android应用程序内部启动Activity过程startActivity的源代码分析 上文介绍了
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是如何配置的 html view plaincopy 1. ltxml versionquot1.0quot encodingquotutf-8quotgt 2. ltmanifest xmlns:androidquothttp://schemas.
android.com/apk/res/androidquot 3. packagequotshy.luo.activityquot 4.
android:versionCodequot1quot 5.
android:versionNamequot1.0quotgt 6. ltapplication
android:iconquotdrawable/iconquot
android:labelquotstring/app_namequotgt 7. ltactivity
android:namequot.MainActivityquot 8.
android:labelquotstring/app_namequotgt 9. ltintent-filtergt 10. ltaction
android:namequotandroid.intent.action.MAINquot /gt 11. ltcategory
android:namequotandroid.intent.category.LAUNCHERquot /gt 12. lt/intent-filtergt 13. lt/activitygt 14. ltactivity
android:namequot.SubActivityquot 15.
android:labelquotstring/sub_activityquotgt 16. ltintent-filtergt 17. ltaction
android:namequotshy.luo.activity.subactivityquot/gt 18. ltcategory
android:namequotandroid.intent.category.DEFAULTquot/gt 19. lt/intent-filtergt 20. lt/activitygt 21. lt/applicationgt 22. lt/manifestgt 这里可以很清楚地看到MainActivity被配置成了应用程序的默认Activity而SubActivity可以通过名称“shy.luo.activity.subactivity”隐式地启动我们来看一下src/shy/luo/activity/MainActivity.java文件的内容可以清楚地看到SubActivity是如何隐式地启动的 java view plaincopy 1. public class MainActivity extends Activity implements OnClickListener 2. ...... 3. 4. Override 5. public void onClickView v 6. ifv.equalsstartButton 7. Intent intent new Intentquotshy.luo.activity.subactivityquot 8. startActivityintent 9. 10. 11. 这里首先创建一个名称为“shy.luo.activity.subactivity”的Intent然后以这个Intent为参数通过调用startActivity函数来实现隐式地启动SubActivity。
有了这些背景知识后我们就来看一下SubActivity启动过程的序列图 点击查看大图 与前面介绍的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文件中 java view plaincopy 1. public class ActivityStack 2. 3. ...... 4. 5. final int startActivityUncheckedLockedActivityRecord r 6. ActivityRecord sourceRecord Uri grantedUriPermissions 7. int grantedMode boolean onlyIfNeeded boolean doResume 8. final Intent intent r.intent 9. final int callingUid r.launchedFromUid 10. 11. int launchFlags intent.getFlags 12. 13. ...... 14. 15. if sourceRecord null 16. ...... 17. else if sourceRecord.launchMode ActivityInfo.LAUNCH_SINGLE_INSTANCE 18. ...... 19. else if r.launchMode ActivityInfo.LAUNCH_SINGLE_INSTANCE 20. ...... 21. 22. 23. if r.resultTo null ampamp launchFlagsampIntent.FLAG_ACTIVITY_NEW_TASK 0 24. ...... 25. 26. 27. boolean addingToTask false 28. if launchFlagsampIntent.FLAG_ACTIVITY_NEW_TASK 0 ampamp 29. launchFlagsampIntent.FLAG_ACTIVITY_MULTIPLE_TASK 0 30. r.launchMode ActivityInfo.LAUNCH_SINGLE_TASK 31. r.launchMode ActivityInfo.LAUNCH_SINGLE_INSTANCE 32. ...... 33. 34. 35. if r.packageName null 36. // If the activity being launched is the same as the one currently 37. // at the top then we need to check if it should only be launched 38. // once. 39. ActivityRecord top topRunningNonDelayedActivityLockednotTop 40. if top null ampamp r.resultTo null 41. if top.realActivity.equalsr.realActivity 42. ...... 43. 44. 45. 46. else 47. ...... 48. 49. 50. boolean newTask false 51. 52. // Should this be considered a new task 53. if r.resultTo null ampamp addingToTask 54. ampamp launchFlagsampIntent.FLAG_ACTIVITY_NEW_TASK 0 55. ...... 56. 57. else if sourceRecord null 58. ...... 59. // An existing activity is starting this new activity so we want 60. // to keep the new one in the same task as the one that is starting 61. // it. 62. r.task sourceRecord.task 63. ...... 64. 65. else 66. ...... 67. 68. 69. ...... 70. 71. startActivityLockedr newTask doResume 72. return START_SUCCESS 73. 74. 75. ...... 76. 77. 这里参数intent的标志位Intent.FLAG_ACTIVITY_NEW_TASK没有设置在配置文件AndriodManifest.xml中SubActivity也没有配置启动模式launchMode于是它就默认标准模式即ActivityInfo.LAUNCH_MULTIPLE因此下面if语句不会执行 java view plaincopy 1. if launchFlagsampIntent.FLAG_ACTIVITY_NEW_TASK 0 ampamp 2. launchFlagsampIntent.FLAG_ACTIVITY_MULTIPLE_TASK 0 3. r.launchMode ActivityInfo.LAUNCH_SINGLE_TASK 4. r.launchMode ActivityInfo.LAUNCH_SINGLE_INSTANCE 5. ...... 6. 于是变量addingToTask为false。
继续往下看 java view plaincopy 1. if r.packageName null 2. // If the activity being launched is the same as the one currently 3. // at the top then we need to check if it should only be launched 4. // once. 5. ActivityRecord top topRunningNonDelayedActivityLockednotTop 6. if top null ampamp r.resultTo null 7. if top.realActivity.equalsr.realActivity 8. ...... 9. 10. 11. 12. 这里看一下当前要启动的Activity是否就是当前堆栈顶端的Activity如果是的话在某些情况下就不用再重新启动了。
函数topRunningNonDelayedActivityLocked返回当前 堆栈顶端的Activity这里即为MainActivity而当前要启动的Activity为SubActivity因此这二者不相等于是跳过里面的if语句。
接着往下执行 java view plaincopy 1. // Should this be considered a new task 2. if r.resultTo null ampamp addingToTask 3. ampamp launchFlagsampIntent.FLAG_ACTIVITY_NEW_TASK 0 4. ...... 5. 6. else if sourceRecord null 7. ...... 8. // An existing activity is starting this new activity so we want 9. // to keep the new one in the same task as the one that is starting 10. // it. 11. r.task sourceRecord.task 12. ...... 13. 14. else 15. ...... 16. 前面说过参数intent的标志位Intent.FLAG_ACTIVITY_NEW_TASK没有设置而这里的sourceRecord即为当前执行启动Activity操作的Activity这里即为MainActivity因此它不为null于是于MainActivity所属的Task设置到r.task中去这里的r即为SubActivity。
看到这里我们就知道SubActivity要和MainActivity运行在同一个Task中了同时变量newTask的值为false。
最后函数进 入startActivityLockedr newTask doResume进一步处理了。
这个函数同样是定义在frameworks/base/services/java/com/
android/server/am/ActivityStack.java文件中 java view plaincopy 1. public class ActivityStack 2. 3. ...... 4. 5. private final void startActivityLockedActivityRecord r boolean newTask 6. boolean doResume 7. final int NH mHistory.size 8. 9. int addPos -1 10. 11. if newTask 12. // If starting in an existing task find where that is... 13. boolean startIt true 14. for int i NH-1 i gt 0 i-- 15. ActivityRecord p ActivityRecordmHistory.geti 16. if p.finishing 17. continue 18. 19. if p.task r.task 20. // Here it is Now if this is not yet visible to the 21. // user then just add it without starting it will 22. // get started when the user navigates back to it. 23. addPos i1 24. if startIt 25. mHistory.addaddPos r 26. r.inHistory true 27. r.task.numActivities 28. mService.mWindowManager.addAppTokenaddPos r r.task.taskId 29. r.info.screenOrientation r.fullscreen 30. if VALIDATE_TOKENS 31. mService.mWindowManager.validateAppTokensmHistory 32. 33. return 34. 35. break 36. 37. if p.fullscreen 38. startIt false 39. 40. 41. 42. 43. ...... 44. 45. // Slot the activity into the history stack and proceed 46. mHistory.addaddPos r 47. r.inHistory true 48. r.frontOfTask newTask 49. r.task.numActivities 50. 51. ...... 52. 53. if doResume 54. resumeTopActivityLockednull 55. 56. 57. 58. ...... 59. 60. 这里传进来的参数newTask为falsedoResume为true。
当newTask为false表示即将要启动的Activity是在原有的Task运行时如果这个原有的Task当前对用户不可见时这时候就不需要继续执行下去了因为即使把这个Activity启动起来用户也看不到还不如先把它保存起来等到下次这个Task对用户可见的时候再启动不迟。
这里这个原有的Task即运行MainActivity的Task当前对用户是可见的因此会继续往下执行。
接下去执行就会把这个SubActivity通过mHistroy.addaddPos r添加到堆栈顶端去然后调用resumeTopActivityLocked进一步操作。
Step 9. ActivityStack.resumeTopActivityLocked 这一步与上一篇文章
Android应用程序启动过程源代码分析的Step 10一致。
但是要注意的是执行到这个函数的时候当前处于堆栈顶端的Activity为SubActivityActivityStack的成员变量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一致。
Step 21. ActivityStack.startSpecificActivityLocked 这一步与上一篇文章
Android应用程序启动过程源代码分析的Step 22就有所不同了这里它不会调用mService.startProcessLocked来创建一个新的进程来启动新的Activity我们来看一下这个函数的实现这个函数定义在frameworks/base/services/java/com/
android/server/am/ActivityStack.java文件中 java view plaincopy 1. public class ActivityStack 2. 3. ...... 4. 5. private final void startSpecificActivityLockedActivityRecord r 6. boolean andResume boolean checkConfig 7. // Is this activitys application already running 8. ProcessRecord app mService.getProcessRecordLockedr.processName 9. r.info.applicationInfo.uid 10. 11. ...... 12. 13. if app null ampamp app.thread null 14. try 15. realStartActivityLockedr app andResume checkConfig 16. return 17. catch RemoteException e 18. ...... 19. 20. 21. 22. ...... 23. 24. 25. 26. ...... 27. 28. 这里由于不是第一次启动应用程序的ActivityMainActivity是这个应用程序第一个启动的Activity所以下面语句 java view plaincopy 1. ProcessRecord app mService.getProcessRecordLockedr.processName 2. nfo.applicationInfo.uid 取回来的app不为null。
在上一篇文章
Android应用程序启动过程源代码分析中我们介绍过在Activity应用程序中的AndroidManifest.xml配置文件中我们没有指定application标签的process属性于是系统就会默认使用package的名称这里就是quotshy.luo.activityquot了。
每一个应用程序都有自己的uid因此这里uid process的组合就可以创建一个全局唯一的ProcessRecord。
这个ProcessRecord是在前面启动MainActivity时创建的因此这里将它取回来并保存在变量app中。
注意我们也可以在AndroidManifest.xml配置文件中指定.
上一篇:
Android应用程序绑定服务(bindService)的过程源代码分析
下一篇:
4种小菜缓解孕妈咪不适