Android源码--startActivityUncheckedLocked

来源:互联网 发布:广州婚纱摄影排名 知乎 编辑:程序博客网 时间:2024/05/23 02:04

startActivityUncheckedLocked(ActivityRecord r,ActivityRecord sourceRecord, int startFlags, boolean doResume,Bundle options)

传入的参数为:

ActivityRecord r:要启动的Activity的ActivityRecord

ActivityRecord sourceRecord:调用者Activity的ActivityRecord

int startFlags:0

boolean doResume:true

Bundle options:调用者传入,一般为null


final Intent intent = r.intent;        final int callingUid = r.launchedFromUid;        final int userId = r.userId;        int launchFlags = intent.getFlags();                // We'll invoke onUserLeaving before onPause only if the launching        // activity did not explicitly state that this is an automated launch.        mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;        if (DEBUG_USER_LEAVING) Slog.v(TAG,                "startActivity() => mUserLeaving=" + mUserLeaving);                // If the caller has asked not to resume at this point, we make note        // of this in the record so that we can skip it when trying to find        // the top running activity.        if (!doResume) {            r.delayedResume = true;        }                ActivityRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)                != 0 ? r : null;

首先得到要启动的Activity的Intent,然后得到调用者的uid,以及要启动的UID,以及Intent中的LaunchFlags,接着判断launchFlags中是否有FLAG_ACTIVITY_NO_USER_ACTION,如果有的话,那么则得到mUserLeaving为true,此标志位是用来判断是否回调onUserLeaving函数的。

接着判断doResume是否为false,如果为false的话,说明需要延迟resume,则将r.delayedResume设置为true,接着判断launchFlags中是否有FLAG_ACTIVITY_PREVIOUS_IS_TOP,如果有的话,那么则将notTop置为r,否则为null


// If the onlyIfNeeded flag is set, then we can do this if the activity        // being launched is the same as the one making the call...  or, as        // a special case, if we do not know the caller then we count the        // current top activity as the caller.        if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {            ActivityRecord checkedCaller = sourceRecord;            if (checkedCaller == null) {                checkedCaller = topRunningNonDelayedActivityLocked(notTop);            }            if (!checkedCaller.realActivity.equals(r.realActivity)) {                // Caller is not the same as launcher, so always needed.                startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;            }        }        if (sourceRecord == null) {            // This activity is not being started from another...  in this            // case we -always- start a new task.            if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {                Slog.w(TAG, "startActivity called from non-Activity context; forcing Intent.FLAG_ACTIVITY_NEW_TASK for: "                      + intent);                launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;            }        } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {            // The original activity who is starting us is running as a single            // instance...  this new activity it is starting must go on its            // own task.            launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;        } 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;        }        if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {            // For whatever reason this activity is being launched into a new            // task...  yet the caller has requested a result back.  Well, that            // is pretty messed up, so instead immediately send back a cancel            // and let the new task continue launched as normal without a            // dependency on its originator.            Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");            sendActivityResultLocked(-1,                    r.resultTo, r.resultWho, r.requestCode,                Activity.RESULT_CANCELED, null);            r.resultTo = null;        }

接着判断startFlags中是否有START_FLAG_ONLY_IF_NEED标志位,那么就会检查调用者的ActivityRecord与要启动的Activity是否是同一个,如果不是同一个的话,那么就将这个START_FLAG_ONLY_IF_NEEDED的标识取消掉。

接着判断sourceRecord是否为空,如果sourceRecord为空的话,那么则会将Intent的launchFlags添加上Intent.FLAG_ACTIVITY_NEW_TASK

如果sourceRecord不为空,那么则判断sourceRecord的LaunchMode是否为SINGLE_INSTANCE,如果是的话,也将launchFlags添上Intent.FLAG_ACTIVITY_NEW_TASK

如果sourceRecord的launchMode不是SINGLE_INSTANCE的话,则判断要启动的Activity是否是SINGLE_INSTANCE或者SINGLE_TASK的,如果是的话,那么将launchFlags添加上Intent.FLAG_ACTIVITY_NEW_TASK

接着判断要启动的Activity的resultTo是否为空,如果不为空而且launchFlags中有Intent.FLAG_ACTIVITY_NEW_TASK的话,那么就将要启动的Activity的resultTo设为null,并且发送取消的消息给调用者的Activity,因为Android不允许两个Task之间通信。

boolean addingToTask = false;        boolean movedHome = false;        TaskRecord reuseTask = null;        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 (taskTop.task.intent == null) {                        // This task was started because of movement of                        // the activity based on affinity...  now that we                        // are actually launching it, we can assign the                        // base intent.                        taskTop.task.setIntent(intent, r.info);                    }                    // If the target task is not in the front, then we need                    // to bring it to the front...  except...  well, with                    // SINGLE_TASK_LAUNCH it's not entirely clear.  We'd like                    // to have the same behavior as if a new instance was                    // being started, which means not bringing it to the front                    // if the caller is not itself in the front.                    ActivityRecord curTop = topRunningNonDelayedActivityLocked(notTop);                    if (curTop != null && curTop.task != taskTop.task) {                        r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);                        boolean callerAtFront = sourceRecord == null                                || curTop.task == sourceRecord.task;                        if (callerAtFront) {                            // We really do want to push this one into the                            // user's face, right now.                            movedHome = true;                            moveHomeToFrontFromLaunchLocked(launchFlags);                            moveTaskToFrontLocked(taskTop.task, r, options);                            options = null;                        }                    }                    // If the caller has requested that the target task be                    // reset, then do so.                    if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {                        taskTop = resetTaskIfNeededLocked(taskTop, r);                    }                    if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED)  != 0) {                        // We don't need to start a new activity, and                        // the client said not to do anything if that                        // is the case, so this is it!  And for paranoia, make                        // sure we have correctly resumed the top activity.                        if (doResume) {                            resumeTopActivityLocked(null, options);                        } else {                            ActivityOptions.abort(options);                        }                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;                    }                    if ((launchFlags &                            (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK))                            == (Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK)) {                        // The caller has requested to completely replace any                        // existing task with its new activity.  Well that should                        // not be too hard...                        reuseTask = taskTop.task;                        performClearTaskLocked(taskTop.task.taskId);                        reuseTask.setIntent(r.intent, r.info);                    } else 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);                        if (top != null) {                            if (top.frontOfTask) {                                // Activity aliases may mean we use different                                // intents for the top activity, so make sure                                // the task now has the identity of the new                                // intent.                                top.task.setIntent(r.intent, r.info);                            }                            logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);                            top.deliverNewIntentLocked(callingUid, r.intent);                        } 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)) {                        // In this case the top activity on the task is the                        // same as the one being launched, so we take that                        // as a request to bring the task to the foreground.                        // If the top activity in the task is the root                        // activity, deliver this new intent to it if it                        // desires.                        if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0                                && taskTop.realActivity.equals(r.realActivity)) {                            logStartActivity(EventLogTags.AM_NEW_INTENT, r, taskTop.task);                            if (taskTop.frontOfTask) {                                taskTop.task.setIntent(r.intent, r.info);                            }                            taskTop.deliverNewIntentLocked(callingUid, r.intent);                        } else if (!r.intent.filterEquals(taskTop.task.intent)) {                            // In this case we are launching the root activity                            // of the task, but with a different intent.  We                            // should start a new instance on top.                            addingToTask = true;                            sourceRecord = taskTop;                        }                    } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {                        // In this case an activity is being launched in to an                        // existing task, without resetting that task.  This                        // is typically the situation of launching an activity                        // from a notification or shortcut.  We want to place                        // the new activity on top of the current task.                        addingToTask = true;                        sourceRecord = taskTop;                    } else if (!taskTop.task.rootWasReset) {                        // In this case we are launching in to an existing task                        // that has not yet been started from its front door.                        // The current task has been brought to the front.                        // Ideally, we'd probably like to place this new task                        // at the bottom of its stack, but that's a little hard                        // to do with the current organization of the code so                        // for now we'll just drop it.                        taskTop.task.setIntent(r.intent, r.info);                    }                    if (!addingToTask && reuseTask == null) {                        // We didn't do anything...  but it was needed (a.k.a., client                        // don't use that intent!)  And for paranoia, make                        // sure we have correctly resumed the top activity.                        if (doResume) {                            resumeTopActivityLocked(null, options);                        } else {                            ActivityOptions.abort(options);                        }                        return ActivityManager.START_TASK_TO_FRONT;                    }                }            }        }

声明三个变量,addingToTask,moveHome,reuseTask。判断launchFlags中存在的Intent.FLAG_ACTIVITY_NEW_TASK,并且没有Intent.FLAG_ACTIVITY_MULTIPLE_TASK或者要启动的Activity是SINGLE_TASK或者SINGLE_INSTANCE的话,那么就会执行上面的逻辑,否则则不会。

判断r.resultTo是否为空,如果为空的话才执行下面代码,否则不执行。

接着通过r.launchMode来找到当前位于Task顶部的Activty,如果是SINGLE_INSTANCE的话,那么就找到Activity,否则则是找到Task顶部的Activity。接着判断taskTop是否为null,如果为Null的话,说明没有启动过这个Activity或者是没有创建过这个TASK,否则就将intent设置到对应的Task中。

接着得到整个ActivityTask最上面的那个ActivityRecord,如果当前最上面的Activity的task和要启动的Activity的Task不一样的话,那么将launchFlags添加Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT,接着判断sourceRecord是否为null,如果不为null并且sourceRecord与curTop的Task一致的话,那么说明,调用者Activity正在最上层显示,那么此时因为两个Activity的Task不一样,所以就会调用moveTaskToFrontLocked将目标Task整个移动到最上面。

接着判断launchFlag中是否有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,如果有的话,则调用resetTaskIfNeededLocked,然后重新计算出当前Task的顶部Activity,然后赋值给taskTop。

接着判断startFlags是否有START_FLAG_ONLY_IF_NEEDED,判断当前要启动的Activity是否启动新的Activity,如果标志位设成true的话,那么就调用resumeTopActivity(null)启动顶部的Activity,也就是什么都不做。

然后判断:launchFlags是否有FLAG_ACTIVITY_NEW_TASK和FLAG_ACTIVITY_CLEAR_TASK,如果有的话,那么就会将reuseTask被赋值成为taskTop.task,也就是说,新运行的这个Activity将重用这个Task,并且调用performClearTaskLocked,然后将Task中的Activity全部清空。否则判断launchFlags中是否有FLAG_ACTIVITY_CLEAR_TOP,或者要启动的Activity的launchMode是否为SINGLE_TASK或者SINGLE_INSTANCE的,如果是的话,那么清掉Task中的Activity,并且找到位于Task中的Activity,如果是一样的话,那么则返回top,也就是说,如果ABCDE,那么从E要启动C,并且C是SINGLE_TASK的话,那么就会清掉DE,然后得到的top就是C了,然后判断top是否为空,如果不为空的话,那么就会调用top.deliverNewIntentLocked回调C的onNewIntent函数,如果不存在的话,那么就将addingToTask设成true,表示要添加到这个Task中,并且将sourceRecord设置成为TaskTop。

否则则判断,launchFlags是否有FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,如果有的话那么设置addingTask=true,并且将sourceRecord设置成taskTop。

最后判断,addingTask是否为false,并且reuseTask是否为null,如果addingTask为false,代表不添加到Task中,而reuseTask为null,代表无重用的Task,那么就直接调用resumeTopActivityLocked

  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) && top.userId == r.userId) {                    if (top.app != null && top.app.thread != null) {                        if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP                            || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) {                            logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);                            // For paranoia, make sure we have correctly                            // resumed the top activity.                            if (doResume) {                                resumeTopActivityLocked(null);                            }                            ActivityOptions.abort(options);                            if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {                                // We don't need to start a new activity, and                                // the client said not to do anything if that                                // is the case, so this is it!                                return ActivityManager.START_RETURN_INTENT_TO_CALLER;                            }                            top.deliverNewIntentLocked(callingUid, r.intent);                            return ActivityManager.START_DELIVERED_TO_TOP;                        }                    }                }            }        } else {            if (r.resultTo != null) {                sendActivityResultLocked(-1,                        r.resultTo, r.resultWho, r.requestCode,                    Activity.RESULT_CANCELED, null);            }            ActivityOptions.abort(options);            return ActivityManager.START_CLASS_NOT_FOUND;        }

判断要启动的Activity的包名是否为空,如果不为空的话,那么得到mHistory最顶部的ActivityRecord,接着判断当前顶部的Activity与要启动的Activity是否相同,并且Activity的进程以及ApplicationThread不为空,接着如果判断launchFlags为FLAG_ACTIVITY_SINGLE_TOP或者LaunchMode为SINGLE_TOP或者SINGLE_TASK的话,那么就调用resumeTopActivityLocked,并且调用top.deliverNewIntentLocked回调Activity的onNewIntent。否则如果包名为空,那么返回CLASS_NOT_FOUND结果。

boolean newTask = false;        boolean keepCurTransition = false;        // Should this be considered a new task?        if (r.resultTo == null && !addingToTask                && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {            if (reuseTask == null) {                // todo: should do better management of integers.                mService.mCurTask++;                if (mService.mCurTask <= 0) {                    mService.mCurTask = 1;                }                r.setTask(new TaskRecord(mService.mCurTask, r.info, intent), null, true);                if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r                        + " in new task " + r.task);            } else {                r.setTask(reuseTask, reuseTask, true);            }            newTask = true;            if (!movedHome) {                moveHomeToFrontFromLaunchLocked(launchFlags);            }                    } else if (sourceRecord != null) {            if (!addingToTask &&                    (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {                // In this case, we are adding the activity to an existing                // task, but the caller has asked to clear that task if the                // activity is already running.                ActivityRecord top = performClearTaskLocked(                        sourceRecord.task.taskId, r, launchFlags);                keepCurTransition = true;                if (top != null) {                    logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);                    top.deliverNewIntentLocked(callingUid, r.intent);                    // For paranoia, make sure we have correctly                    // resumed the top activity.                    if (doResume) {                        resumeTopActivityLocked(null);                    }                    ActivityOptions.abort(options);                    return ActivityManager.START_DELIVERED_TO_TOP;                }            } else if (!addingToTask &&                    (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {                // In this case, we are launching an activity in our own task                // that may already be running somewhere in the history, and                // we want to shuffle it to the front of the stack if so.                int where = findActivityInHistoryLocked(r, sourceRecord.task.taskId);                if (where >= 0) {                    ActivityRecord top = moveActivityToFrontLocked(where);                    logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);                    top.updateOptionsLocked(options);                    top.deliverNewIntentLocked(callingUid, r.intent);                    if (doResume) {                        resumeTopActivityLocked(null);                    }                    return ActivityManager.START_DELIVERED_TO_TOP;                }            }            // 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.setTask(sourceRecord.task, sourceRecord.thumbHolder, false);            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r                    + " in existing task " + r.task);        } else {            // This not being started from an existing activity, and not part            // of a new task...  just put it in the top task, though these days            // this case should never happen.            final int N = mHistory.size();            ActivityRecord prev =                N > 0 ? mHistory.get(N-1) : null;            r.setTask(prev != null                    ? prev.task                    : new TaskRecord(mService.mCurTask, r.info, intent), null, true);            if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r                    + " in new guessed " + r.task);        }

创建两个变量,newTask以及keepCurTransition,newTask标识着是否需要创建一个新的Task:

1.判断r.resultTo是否为null,如果为null,并且addingToTask为false,launchFlag被置为FLAG_ACTIVITY_NEW_TASK的话,然后判断reuseTask是否为空,如果为空的话,说明没有可以重用的Task,那么就需要创建一个新的Task,如果reuseTask不为空的话,那么说明有重用的Task,那么就直接设置Task即可。然后判断moveHome,如果moveHome为false的话,那么就会调用moveHomeToFrontLaunchLocked

2.否则判断sourceReocrd是否为空,如果不为空的话,那么判断addingToTask是否为false,并且launchFlags中是否有FLAG_ACTIVITY_CLEAR_TOP,如果存在的话,那么就调用performClearTaskLocked函数,清除掉Task上面的Activity,然后得到Task的顶部的Activity,如果该Activity不为空的话,那么就会调用top.delieverNewIntentLocked,回调onNewIntent

3.否则判断addingToTask是否为false,并且launcFlag是否为FLAG_ACTIVITY_REORDER_TO_FRONT,如果存在该标志位的话,接着通过findActivityInHistoryLocked得到与TaskID还有r相同的ActivityRecord,如果相同的话,那么则返回Activity的Index,如果index大于等于0的话,那么就会将Activity移到History的顶部,然后回调onNewIntent,然后设置它的Task。

4.否则得到mHistory最顶部的Activity,如果Activity是否为null,如果不为null的话,那么就设置r.taskId为Activity的ID,如果为null的话,那么就创建一个新的TaskRecord,然后通过r.setTask设置进去。



0 0
原创粉丝点击