解开Android应用程序组件Activity的“singleTask”之谜(3)

前面我们在两篇文章Android应用程序启动过程源代码分析和Android应用程序内部启动Activity过程(startActivity)的源代码分析时,分别在Step 9和Step 8中分析了Activity在启动过程中与任务相关的函数ActivityStack.startActivityUncheckedLocked函数中,它定义在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();              ......              ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)              != 0 ? r : null;              ......              if (sourceRecord == null) {               ......           } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {               ......           } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE              || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {               // The activity being started is a single instance...  it always                // gets launched into its own task.                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;           }              ......              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 bring to front is requested, and no result is requested, and                   // we can find a task that was started with this same                   // component, then instead of launching bring that one to the front.                   if (r.resultTo == null) {                      // See if there is a task to bring to the front.  If this is                       // a SINGLE_INSTANCE activity, there can be one and only one                       // instance of it in the history, and it is always in its own                       // unique task, so we do a special search.                       ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE                          ? findTaskLocked(intent, r.info)                          : findActivityLocked(intent, r.info);                      if (taskTop != null) {                                                    ......                             if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0                              || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK                              || r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {                                  // In this situation we want to remove all activities                                   // from the task up to the one being started.  In most                                   // cases this means we are resetting the task to its                                   // initial state.                                   ActivityRecord top = performClearTaskLocked(                                      taskTop.task.taskId, r, launchFlags, true);                                  if (top != null) {                                      ......                                  } else {                                      // A special case: we need to                                       // start the activity because it is not currently                                       // running, and the caller has asked to clear the                                       // current task to have this activity at the top.                                       addingToTask = true;                                      // Now pretend like this activity is being started                                       // by the top of its task, so it is put in the                                       // right place.                                       sourceRecord = taskTop;                                  }                          } else if (r.realActivity.equals(taskTop.task.realActivity)) {                              ......                          } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {                              ......                          } else if (!taskTop.task.rootWasReset) {                              ......                          }                                                    ......                      }                  }           }              ......              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)) {                      if (top.app != null && top.app.thread != null) {                          ......                      }                  }              }              } else {              ......           }              boolean newTask = false;              // Should this be considered a new task?            if (r.resultTo == null && !addingToTask              && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {                // todo: should do better management of integers.                             mService.mCurTask++;                            if (mService.mCurTask <= 0) {                                 mService.mCurTask = 1;                            }                            r.task = new TaskRecord(mService.mCurTask, r.info, intent,                                (r.info.flags&ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0);                            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r                               + " in new task " + r.task);                            newTask = true;                            if (mMainStack) {                                 mService.addRecentTaskLocked(r.task);                            }           } else if (sourceRecord != null) {              if (!addingToTask &&                  (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {                   ......              } else if (!addingToTask &&                  (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {                   ......              }              // 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;       }          ......      }  

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

接下来的这个if语句:

   if (sourceRecord == null) {   ......      } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {   ......      } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE         || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {   // The activity being started is a single instance...  it always    // gets launched into its own task.    launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;      }  

这里变量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语句中,执行:

  ActivityRecord taskTop = r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE   ? findTaskLocked(intent, r.info)   : findActivityLocked(intent, r.info)  

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

public class ActivityStack {          ......          /**      * Returns the top activity in any existing task matching the given      * Intent.  Returns null if no such task is found.      */       private ActivityRecord findTaskLocked(Intent intent, ActivityInfo info) {           ComponentName cls = intent.getComponent();           if (info.targetActivity != null) {               cls = new ComponentName(info.packageName, info.targetActivity);           }              TaskRecord cp = null;              final int N = mHistory.size();           for (int i=(N-1); i>=0; i--) {               ActivityRecord r = (ActivityRecord)mHistory.get(i);               if (!r.finishing && r.task != cp                   && r.launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE) {                       cp = r.task;                       //Slog.i(TAG, "Comparing existing cls=" + r.task.intent.getComponent().flattenToShortString()                        //        + "/aff=" + r.task.affinity + " to new cls="                        //        + intent.getComponent().flattenToShortString() + "/aff=" + taskAffinity);                        if (r.task.affinity != null) {                           if (r.task.affinity.equals(info.taskAffinity)) {                               //Slog.i(TAG, "Found matching affinity!");                                return r;                           }                       } else if (r.task.intent != null                           && r.task.intent.getComponent().equals(cls)) {                               //Slog.i(TAG, "Found matching class!");                                //dump();                                //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);                                return r;                       } else if (r.task.affinityIntent != null                           && r.task.affinityIntent.getComponent().equals(cls)) {                               //Slog.i(TAG, "Found matching class!");                                //dump();                                //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);                                return r;                       }               }           }              return null;       }          ......      }  

linux

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wwgxdw.html