再接下来,就是运行模拟器来运行我们的例子了。关于如何在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. 箭头函数的基础使用
  2. Python技巧匿名函数、回调函数和高阶函数
  3. android 视频通话 项目 源码
  4. findViewById()使用常见错误
  5. Android(安卓)- ListActivity 单击事件的响应
  6. Android应用程序启动过程源代码分析
  7. Android驱动(一)硬件访问服务学习之(一)Android通过JNI访问硬件
  8. android WebView总结
  9. Android(安卓)利用JNI调用Android(安卓)Java代码函数

随机推荐

  1. Android复习(八)
  2. Android上的log,日志相关
  3. android 软键盘隐藏 activity初始化时edi
  4. Android(安卓)远程链接 daemon not runni
  5. android中的内存泄露
  6. android studio升级时提示 Connection fa
  7. webrtc 针对 android 平台的编译和运行
  8. android开发BUG集
  9. [置顶] 自定义的解压进度条 关于Progress
  10. Android自定义Toast,并解决toast不重复显