再接下来,就是运行模拟器来运行我们的例子了。关于如何在Android源代码工程中运行模拟器,请参考 在Ubuntu上下载、编译和安装Android最新源代码 一文。
执行以下命令启动模拟器:
        
  1. USER-NAME@MACHINE-NAME:~/Android$emulator
模拟器启动起,就可以App Launcher中找到Task应用程序图标,接着把它启动起来:

点击中间的按钮,就会以"singleTask"的方式来启动SubActivity:

现在,我们如何来确认SubActivity是不是在新的任务中启动并且位于这个新任务的堆栈底部呢?Android源代码工程为我们准备了adb工具,可以查看模拟器上系统运行的状况,执行下面的命令查看;

        
  1. USER-NAME@MACHINE-NAME:~/Android$adbshelldumpsysactivity

这个命令输出的内容比较多,这里我们只关心TaskRecord部分:

        
  1. Runningactivities(mostrecentfirst):
  2. TaskRecord{4070d8f8#3Ashy.luo.task}
  3. Run#2:HistoryRecord{406a13f8shy.luo.task/.SubActivity}
  4. Run#1:HistoryRecord{406a0e00shy.luo.task/.MainActivity}
  5. TaskRecord{4067a510#2Acom.android.launcher}
  6. Run#0:HistoryRecord{40677518com.android.launcher/com.android.launcher2.Launcher}

果然,SubActivity和MainActivity都是运行在TaskRecord#3中,并且SubActivity在MainActivity的上面。这是怎么回事呢?碰到这种情况,Linus Torvalds告诫我们:Read the fucking source code;去年张麻子又说:枪在手,跟我走;我们没有枪,但是有source code,因此,我要说:跟着代码走。

前面我们在两篇文章Android应用程序启动过程源代码分析和Android应用程序内部启动Activity过程(startActivity)的源代码分析时,分别在Step 9和Step 8中分析了Activity在启动过程中与任务相关的函数ActivityStack.startActivityUncheckedLocked函数中,它定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

        
  1. publicclassActivityStack{
  2. ......
  3. finalintstartActivityUncheckedLocked(ActivityRecordr,
  4. ActivityRecordsourceRecord,Uri[]grantedUriPermissions,
  5. intgrantedMode,booleanonlyIfNeeded,booleandoResume){
  6. finalIntentintent=r.intent;
  7. finalintcallingUid=r.launchedFromUid;
  8. intlaunchFlags=intent.getFlags();
  9. ......
  10. ActivityRecordnotTop=(launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
  11. !=0?r:null;
  12. ......
  13. if(sourceRecord==null){
  14. ......
  15. }elseif(sourceRecord.launchMode==ActivityInfo.LAUNCH_SINGLE_INSTANCE){
  16. ......
  17. }elseif(r.launchMode==ActivityInfo.LAUNCH_SINGLE_INSTANCE
  18. ||r.launchMode==ActivityInfo.LAUNCH_SINGLE_TASK){
  19. //Theactivitybeingstartedisasingleinstance...italways
  20. //getslaunchedintoitsowntask.
  21. launchFlags|=Intent.FLAG_ACTIVITY_NEW_TASK;
  22. }
  23. ......
  24. booleanaddingToTask=false;
  25. if(((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK)!=0&&
  26. (launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK)==0)
  27. ||r.launchMode==ActivityInfo.LAUNCH_SINGLE_TASK
  28. ||r.launchMode==ActivityInfo.LAUNCH_SINGLE_INSTANCE){
  29. //Ifbringtofrontisrequested,andnoresultisrequested,and
  30. //wecanfindataskthatwasstartedwiththissame
  31. //component,theninsteadoflaunchingbringthatonetothefront.
  32. if(r.resultTo==null){
  33. //Seeifthereisatasktobringtothefront.Ifthisis
  34. //aSINGLE_INSTANCEactivity,therecanbeoneandonlyone
  35. //instanceofitinthehistory,anditisalwaysinitsown
  36. //uniquetask,sowedoaspecialsearch.
  37. ActivityRecordtaskTop=r.launchMode!=ActivityInfo.LAUNCH_SINGLE_INSTANCE
  38. ?findTaskLocked(intent,r.info)
  39. :findActivityLocked(intent,r.info);
  40. if(taskTop!=null){
  41. ......
  42. if((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP)!=0
  43. ||r.launchMode==ActivityInfo.LAUNCH_SINGLE_TASK
  44. ||r.launchMode==ActivityInfo.LAUNCH_SINGLE_INSTANCE){
  45. //Inthissituationwewanttoremoveallactivities
  46. //fromthetaskuptotheonebeingstarted.Inmost
  47. //casesthismeansweareresettingthetasktoits
  48. //initialstate.
  49. ActivityRecordtop=performClearTaskLocked(
  50. taskTop.task.taskId,r,launchFlags,true);
  51. if(top!=null){
  52. ......
  53. }else{
  54. //Aspecialcase:weneedto
  55. //starttheactivitybecauseitisnotcurrently
  56. //running,andthecallerhasaskedtoclearthe
  57. //currenttasktohavethisactivityatthetop.
  58. addingToTask=true;
  59. //Nowpretendlikethisactivityisbeingstarted
  60. //bythetopofitstask,soitisputinthe
  61. //rightplace.
  62. sourceRecord=taskTop;
  63. }
  64. }elseif(r.realActivity.equals(taskTop.task.realActivity)){
  65. ......
  66. }elseif((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)==0){
  67. ......
  68. }elseif(!taskTop.task.rootWasReset){
  69. ......
  70. }
  71. ......
  72. }
  73. }
  74. }
  75. ......
  76. if(r.packageName!=null){
  77. //Iftheactivitybeinglaunchedisthesameastheonecurrently
  78. //atthetop,thenweneedtocheckifitshouldonlybelaunched
  79. //once.
  80. ActivityRecordtop=topRunningNonDelayedActivityLocked(notTop);
  81. if(top!=null&&r.resultTo==null){
  82. if(top.realActivity.equals(r.realActivity)){
  83. if(top.app!=null&&top.app.thread!=null){
  84. ......
  85. }
  86. }
  87. }
  88. }else{
  89. ......
  90. }
  91. booleannewTask=false;
  92. //Shouldthisbeconsideredanewtask?
  93. if(r.resultTo==null&&!addingToTask
  94. &&(launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK)!=0){
  95. //todo:shoulddobettermanagementofintegers.
  96. mService.mCurTask++;
  97. if(mService.mCurTask<=0){
  98. mService.mCurTask=1;
  99. }
  100. r.task=newTaskRecord(mService.mCurTask,r.info,intent,
  101. (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH)!=0);
  102. if(DEBUG_TASKS)Slog.v(TAG,"Startingnewactivity"+r
  103. +"innewtask"+r.task);
  104. newTask=true;
  105. if(mMainStack){
  106. mService.addRecentTaskLocked(r.task);
  107. }
  108. }elseif(sourceRecord!=null){
  109. if(!addingToTask&&
  110. (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP)!=0){
  111. ......
  112. }elseif(!addingToTask&&
  113. (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)!=0){
  114. ......
  115. }
  116. //Anexistingactivityisstartingthisnewactivity,sowewant
  117. //tokeepthenewoneinthesametaskastheonethatisstarting
  118. //it.
  119. r.task=sourceRecord.task;
  120. ......
  121. }else{
  122. ......
  123. }
  124. ......
  125. startActivityLocked(r,newTask,doResume);
  126. returnSTART_SUCCESS;
  127. }
  128. ......
  129. }

首先是获得用来启动Activity的Intent的Flags,并且保存在launchFlags变量中,这里,launcFlags的Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP位没有置位,因此,notTop为null。

接下来的这个if语句:

        
  1. if(sourceRecord==null){
  2. ......
  3. }elseif(sourceRecord.launchMode==ActivityInfo.LAUNCH_SINGLE_INSTANCE){
  4. ......
  5. }elseif(r.launchMode==ActivityInfo.LAUNCH_SINGLE_INSTANCE
  6. ||r.launchMode==ActivityInfo.LAUNCH_SINGLE_TASK){
  7. //Theactivitybeingstartedisasingleinstance...italways
  8. //getslaunchedintoitsowntask.
  9. launchFlags|=Intent.FLAG_ACTIVITY_NEW_TASK;
  10. }

这里变量r的类型为ActivityRecord,它表示即将在启动的Activity,在这个例子中,即为SubActivity,因此,这里的r.launchMode等于ActivityInfo.LAUNCH_SINGLE_TASK,于是,无条件将launchFlags的Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP位置为1,表示这个SubActivity要在新的任务中启动,但是别急,还要看看其它条件是否满足,如果条件都满足,才可以在新的任务中启动这个SubActivity。
接下将addingToTask变量初始化为false,这个变量也将决定是否要将SubActivity在新的任务中启动,从名字我们就可以看出,默认不增加到原有的任务中启动,即要在新的任务中启动。这里的r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK条成立,条件r.resultTo == null也成立,它表这个Activity不需要将结果返回给启动它的Activity。于是会进入接下来的if语句中,执行:

        
  1. ActivityRecordtaskTop=r.launchMode!=ActivityInfo.LAUNCH_SINGLE_INSTANCE
  2. ?findTaskLocked(intent,r.info)
  3. :findActivityLocked(intent,r.info)

这里的条件r.launchMode !=ActivityInfo.LAUNCH_SINGLE_INSTANCE成立,于是执行findTaskLocked函数,这个函数也是定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

        
  1. publicclassActivityStack{
  2. ......
  3. /**
  4. *Returnsthetopactivityinanyexistingtaskmatchingthegiven
  5. *Intent.Returnsnullifnosuchtaskisfound.
  6. */
  7. privateActivityRecordfindTaskLocked(Intentintent,ActivityInfoinfo){
  8. ComponentNamecls=intent.getComponent();
  9. if(info.targetActivity!=null){
  10. cls=newComponentName(info.packageName,info.targetActivity);
  11. }
  12. TaskRecordcp=null;
  13. finalintN=mHistory.size();
  14. for(inti=(N-1);i>=0;i--){
  15. ActivityRecordr=(ActivityRecord)mHistory.get(i);
  16. if(!r.finishing&&r.task!=cp
  17. &&r.launchMode!=ActivityInfo.LAUNCH_SINGLE_INSTANCE){
  18. cp=r.task;
  19. //Slog.i(TAG,"Comparingexistingcls="+r.task.intent.getComponent().flattenToShortString()
  20. //+"/aff="+r.task.affinity+"tonewcls="
  21. //+intent.getComponent().flattenToShortString()+"/aff="+taskAffinity);
  22. if(r.task.affinity!=null){
  23. if(r.task.affinity.equals(info.taskAffinity)){
  24. //Slog.i(TAG,"Foundmatchingaffinity!");
  25. returnr;
  26. }
  27. }elseif(r.task.intent!=null
  28. &&r.task.intent.getComponent().equals(cls)){
  29. //Slog.i(TAG,"Foundmatchingclass!");
  30. //dump();
  31. //Slog.i(TAG,"ForIntent"+intent+"bringingtotop:"+r.intent);
  32. returnr;
  33. }elseif(r.task.affinityIntent!=null
  34. &&r.task.affinityIntent.getComponent().equals(cls)){
  35. //Slog.i(TAG,"Foundmatchingclass!");
  36. //dump();
  37. //Slog.i(TAG,"ForIntent"+intent+"bringingtotop:"+r.intent);
  38. returnr;
  39. }
  40. }
  41. }
  42. returnnull;
  43. }
  44. ......
  45. }

这个函数无非就是根据即将要启动的SubActivity的taskAffinity属性值在系统中查找这样的一个Task:Task的affinity属性值与即将要启动的Activity的taskAffinity属性值一致。如果存在,就返回这个Task堆栈顶端的Activity回去。在上面的AndroidManifest.xml文件中,没有配置MainActivity和SubActivity的taskAffinity属性,于是它们的taskAffinity属性值就默认为父标签application的taskAffinity属性值,这里,标签application的taskAffinity也没有配置,于是它们就默认为包名,即"shy.luo.task"。由于在启动SubActivity之前,MainActivity已经启动,MainActivity启动的时候,会在一个新的任务里面启动,而这个新的任务的affinity属性就等于它的第一个Activity的taskAffinity属性值。于是,这个函数会动回表示MainActivity的ActivityRecord回去.

回到前面的startActivityUncheckedLocked函数中,这里的taskTop就表示MainActivity,它不为null,于是继续往前执行。由于条件r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK成立,于是执行下面语句:

        
  1. ActivityRecordtop=performClearTaskLocked(
  2. kTop.task.taskId,r,launchFlags,true);

函数performClearTaskLocked也是定义在frameworks/base/services/java/com/android/server/am/ActivityStack.java文件中:

        
  1. publicclassActivityStack{
  2. ......
  3. /**
  4. *Performclearoperationasrequestedby
  5. *{@linkIntent#FLAG_ACTIVITY_CLEAR_TOP}:searchfromthetopofthe
  6. *stacktothegiventask,thenlookfor
  7. *aninstanceofthatactivityinthestackand,iffound,finishall
  8. *activitiesontopofitandreturntheinstance.
  9. *
  10. *@paramnewRDescriptionofthenewactivitybeingstarted.
  11. *@returnReturnstheoldactivitythatshouldbecontinuetobeused,
  12. *ornullifnonewasfound.
  13. */
  14. privatefinalActivityRecordperformClearTaskLocked(inttaskId,
  15. ActivityRecordnewR,intlaunchFlags,booleandoClear){
  16. inti=mHistory.size();
  17. //Firstfindtherequestedtask.
  18. while(i>0){
  19. i--;
  20. ActivityRecordr=(ActivityRecord)mHistory.get(i);
  21. if(r.task.taskId==taskId){
  22. i++;
  23. break;
  24. }
  25. }
  26. //Nowclearit.
  27. while(i>0){
  28. i--;
  29. ActivityRecordr=(ActivityRecord)mHistory.get(i);
  30. if(r.finishing){
  31. continue;
  32. }
  33. if(r.task.taskId!=taskId){
  34. returnnull;
  35. }
  36. if(r.realActivity.equals(newR.realActivity)){
  37. //Hereitis!Nowfinisheverythinginfront...
  38. ActivityRecordret=r;
  39. if(doClear){
  40. while(i<(mHistory.size()-1)){
  41. i++;
  42. r=(ActivityRecord)mHistory.get(i);
  43. if(r.finishing){
  44. continue;
  45. }
  46. if(finishActivityLocked(r,i,Activity.RESULT_CANCELED,
  47. null,"clear")){
  48. i--;
  49. }
  50. }
  51. }
  52. //Finally,ifthisisanormallaunchmode(thatis,not
  53. //expectingonNewIntent()),thenwewillfinishthecurrent
  54. //instanceoftheactivitysoanewfreshonecanbestarted.
  55. if(ret.launchMode==ActivityInfo.LAUNCH_MULTIPLE
  56. &&(launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP)==0){
  57. if(!ret.finishing){
  58. intindex=indexOfTokenLocked(ret);
  59. if(index>=0){
  60. finishActivityLocked(ret,index,Activity.RESULT_CANCELED,
  61. null,"clear");
  62. }
  63. returnnull;
  64. }
  65. }
  66. returnret;
  67. }
  68. }
  69. returnnull;
  70. }
  71. ......
  72. }

这个函数中作用无非就是找到ID等于参数taskId的任务,然后在这个任务中查找是否已经存在即将要启动的Activity的实例,如果存在,就会把这个Actvity实例上面直到任务堆栈顶端的Activity通过调用finishActivityLocked函数将它们结束掉。在这个例子中,就是要在属性值affinity等于"shy.luo.task"的任务中看看是否存在SubActivity类型的实例,如果有,就把它上面的Activity都结束掉。这里,属性值affinity等于"shy.luo.task"的任务只有一个MainActivity,而且它不是SubActivity的实例,所以这个函数就返回null了。

更多相关文章

  1. TextView的XML属性说明全析 ---Android基础篇
  2. Android 利用JNI调用Android Java代码函数
  3. android之TextView属性
  4. Android EditText inputType属性
  5. Android中的singleLine(单行显示)和ellipsize属性
  6. android taskAffinity属性
  7. android xml常规布局属性

随机推荐

  1. 谈中型项目下的编码技巧二
  2. Android(安卓)LinearLayout 点击背景颜色
  3. Android(安卓)使用AES/CBC/PKCS7Padding
  4. android ListView向上滑动隐藏标题,下拉显
  5. Android中使用Geocoding API
  6. Android实现的视频背景
  7. Android(安卓)开发学习笔记(一)—— 四大组
  8. OkHttp得拦截机制
  9. Android(安卓)AMS(一) App启动过程之Task
  10. 多个项目Module全局配置