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设置进去。
- Android源码--startActivityUncheckedLocked
- ActivityStackSupervisor.StartActivityUncheckedLocked()函数分析
- Android源码
- android源码
- android源码
- android源码
- android 源码
- android 源码
- android 源码
- Android 源码
- android源码
- android 源码
- android 源码
- android 源码
- android 源码
- Android源码
- Android源码
- android 源码
- C++ std::pair 与 std::make_pair
- Storm – Kafka – Cassandra for Big Data System
- OpenGL环境设置
- kettle4.1源码研究
- Android 圆形ImagView
- Android源码--startActivityUncheckedLocked
- 选项卡选中状态的实现及其多个选项时按钮的状态切换((每个选项其实都是按钮))
- for循环,unsigned short
- MySQL索引背后的数据结构及算法原理
- OpenMP 之reduction 子句求数值积分圆周率(pi)(学习笔记)
- 类的成员函数是否可以做为回调函数?
- wps文档漫游 如何设置缺省不打开
- App测试要点
- 误删除手机照片如何恢复