在移动应用开发中,Android四大组件之一Activity是最常用的。很多界面,如:闪屏、主界面、次功能界面等都需要Activity来作为主要的载体;界面与界面之间,即不同的Activity之间也都存在跳转切换,弄懂这其中跳转切换原理,将有助于我们更好的理解Android中Activity之间的交互逻辑,从而更好的开发Android应用。本篇博文将会重点介绍Android应用中的Activity的启动流程。
在开始介绍之前,我们需要了解一些概念,如:
ActivityThread: 应用的启动入口类,当应用启动,会首先执行其main方法,开启主线程消息循环机制。 ApplicationThread: ActivityThread的内部类,主要与系统进程AMS通信,从而对应用进程的具体Activity操作进行管理。 Instrumentation: ActivityThread的属性变量,主要辅助ActivityThread类调用Activity的生命周期相关方法。 ActivityManagerService(AMS): Activity管理系统服务类,主要是对所有的Activity进行管理。 ActivityStack: Activity任务栈,AMS的属性变量,AMS中Activtiy的实际管理者。Activity启动流程图:
此流程图,主要是根据Android源码中代码执行顺序来梳理的。浅绿色部分为应用进程,浅蓝色部分为系统服务进程,两个进程间通过Binder驱动来进行通信,第一次Binder通信主要的类有:ActivityManagerService(AMS),ActivityManagerNative(AMN),ActivityManagerProxy(AMP);第二次Binder通信主要的类有:ApplicationThread(AT),ApplicationThreadNative(ATN),ApplicationThreadProxy(ATP)。
根据上面流程图,下面让我们一起来看看源码,首先从Activity的startActivity开始:
@Override public void startActivity(Intent intent) { startActivity(intent, null); } @Override public void startActivity(Intent intent, Bundle options) { if (options != null) { startActivityForResult(intent, -1, options); } else { // Note we want to go through this call for compatibility with // applications that may have overridden the method. startActivityForResult(intent, -1); } } public void startActivityForResult(Intent intent, int requestCode) { startActivityForResult(intent, requestCode, null); } public void startActivityForResult(Intent intent, int requestCode, Bundle options) { if (mParent == null) {//1.核心代码 Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, this, intent, requestCode, options); if (ar != null) { mMainThread.sendActivityResult( mToken, mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } if (requestCode >= 0) { // If this start is requesting a result, we can avoid making // the activity visible until the result is received. Setting // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the // activity hidden during this time, to avoid flickering. // This can only be done when a result is requested because // that guarantees we will get information back when the // activity is finished, no matter what happens to it. mStartedActivity = true; } } else {//2.核心代码 if (options != null) { mParent.startActivityFromChild(this, intent, requestCode, options); } else { // Note we want to go through this method for compatibility with // existing applications that may have overridden it. mParent.startActivityFromChild(this, intent, requestCode); } } }
在Activity源码中,startActivity之后都会调用startActivityForResult;在注释1处,当mParent为空时,会直接调用Instrumentation中的execStartActivity方法,当mParent不为空时,调用mParent.startActivityFromChild方法。通过跟踪查找发现,mParent也是Activity,在Activity attach的时候会初始化,从ActivityRecord中获得值。我们继续来看看startActivityFromChild方法
public void startActivityFromChild(Activity child, Intent intent, int requestCode) { startActivityFromChild(child, intent, requestCode, null); } public void startActivityFromChild(Activity child, Intent intent, int requestCode, Bundle options) { Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity( this, mMainThread.getApplicationThread(), mToken, child, intent, requestCode, options); if (ar != null) { mMainThread.sendActivityResult( mToken, child.mEmbeddedID, requestCode, ar.getResultCode(), ar.getResultData()); } }
由此发现,startActivityForResult之后都调用了Instrumentation中的execStartActivity方法。我们继续来看看execStartActivity方法:
public ActivityResult execStartActivity( Context who, IBinder contextThread, IBinder token, Activity target, Intent intent, int requestCode, Bundle options) { IApplicationThread whoThread = (IApplicationThread) contextThread; ...... try { intent.setAllowFds(false); intent.migrateExtraStreamToClipData(); //核心代码 int result = ActivityManagerNative.getDefault() .startActivity(whoThread, intent, intent.resolveTypeIfNeeded(who.getContentResolver()), token, target != null ? target.mEmbeddedID : null, requestCode, 0, null, null, options); checkStartActivityResult(result, intent); } catch (RemoteException e) { } return null; }
这里主要是调用了ActivityManagerNative.getDefault()中的startActivity(…)方法,这里就涉及到Binder的一次跨进程通信,通过跨进程通信调用了ActivityManagerService中的startActivity方法。具体Binder怎么跨进程通信的,我已写过文章 Android跨进程通信方式(IPC)解析,想了解的同学,可以点击看看。下面我们继续来看看AMS中的startActivity方法:
public final int startActivity(IApplicationThread caller, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, String profileFile, ParcelFileDescriptor profileFd, Bundle options) { enforceNotIsolatedCaller("startActivity"); ...... return mMainStack.startActivityMayWait(caller, -1, intent, resolvedType, resultTo, resultWho, requestCode, startFlags, profileFile, profileFd, null, null, options, userId); }
在AMS的startActivity方法中,又调用ActivityStack中的startActivityMayWait()方法,我们再来看看ActivityStack的源码:
final int startActivityMayWait(IApplicationThread caller, int callingUid, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int startFlags, String profileFile, ParcelFileDescriptor profileFd, WaitResult outResult, Configuration config, Bundle options, int userId) { ...... //核心代码 int res = startActivityLocked(caller, intent, resolvedType, aInfo, resultTo, resultWho, requestCode, callingPid, callingUid, startFlags, options, componentSpecified, null); ...... return res; } }
我们这里主要分析启动流程,所以省略掉部分细节。让我们继续看ActivityStack中的startActivityLocked()方法
final int startActivityLocked(IApplicationThread caller, Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid, int startFlags, Bundle options, boolean componentSpecified, ActivityRecord[] outActivity) { ...... //创建一个新的ActivityRecord ActivityRecord r = new ActivityRecord(mService, this, callerApp, callingUid, intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho, requestCode, componentSpecified); ...... err = startActivityUncheckedLocked(r, sourceRecord, startFlags, true, options); ...... return err; }
同上,也省略的部分细节。我们继续
final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord, int startFlags, boolean doResume, Bundle options) { ...... if (sourceRecord == null) { if ((launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) == 0) { launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) { launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } else if (r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE || r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK) { launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } ......//省略代码:Activity四种启动模式standard,singleTop,singleTask,singleInstance的判断 if (sourceRecord != null) { ....... 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 { ...... } ...... return ActivityManager.START_SUCCESS; }
在startActivityUncheckedLocked()方法中,主要针对Activity的启动模式进行了检测判断,从而启动Activity。我们知道,Activity有四种启动模式,分别为standard,singleTop,singleTask和singleInstance,但这里我们主要是分析Activity的启动流程,所以具体启动模式的判断逻辑细节,这里就不展开分析了。我们主要来看一下,把Activity启动放到栈顶的方法resumeTopActivityLocked()
final boolean resumeTopActivityLocked(ActivityRecord prev) { return resumeTopActivityLocked(prev, null); } final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) { //找到一个栈顶的未finish的Activity的ActivityRecord ActivityRecord next = topRunningActivityLocked(null); ...... if (next == null) {//栈顶无Activity,直接启动Launcher if (mMainStack) { ActivityOptions.abort(options); return mService.startHomeActivityLocked(0); } } ...... //如果Activity所在的进程已经存在 if (next.app != null && next.app.thread != null) { ...... try { ....... //重新显示Activity if (next.newIntents != null) { next.app.thread.scheduleNewIntent(next.newIntents, next.appToken); } EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, System.identityHashCode(next), next.task.taskId, next.shortComponentName); next.sleeping = false; showAskCompatModeDialogLocked(next); next.app.pendingUiClean = true; //执行Activity onResume方法 next.app.thread.scheduleResumeActivity(next.appToken, mService.isNextTransitionForward()); checkReadyForSleepLocked(); } catch (Exception e) { //如果启动异常,就重启Activity if (DEBUG_STATES) Slog.v(TAG, "Resume failed; resetting state to " + lastState + ": " + next); next.state = lastState; mResumedActivity = lastResumedActivity; Slog.i(TAG, "Restarting because process died: " + next); if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; } else { if (SHOW_APP_STARTING_PREVIEW && mMainStack) { mService.mWindowManager.setAppStartingWindow( next.appToken, next.packageName, next.theme, mService.compatibilityInfoForPackageLocked( next.info.applicationInfo), next.nonLocalizedLabel, next.labelRes, next.icon, next.windowFlags, null, true); } } startSpecificActivityLocked(next, true, false);//核心代码,重启Activity return true; } // From this point on, if something goes wrong there is no way // to recover the activity. try { next.visible = true; completeResumeLocked(next); } catch (Exception e) { // If any exception gets thrown, toss away this // activity and try the next one. Slog.w(TAG, "Exception thrown during resume of " + next, e); requestFinishActivityLocked(next.appToken, Activity.RESULT_CANCELED, null, "resume-exception"); return true; } // Didn't need to use the icicle, and it is now out of date. if (DEBUG_SAVED_STATE) Slog.i(TAG, "Resumed activity; didn't need icicle of: " + next); next.icicle = null; next.haveState = false; next.stopped = false; } else { //Activity所在的进程不存在,启动Activity if (!next.hasBeenLaunched) { next.hasBeenLaunched = true; } else { if (SHOW_APP_STARTING_PREVIEW) { mService.mWindowManager.setAppStartingWindow( next.appToken, next.packageName, next.theme, mService.compatibilityInfoForPackageLocked( next.info.applicationInfo), next.nonLocalizedLabel, next.labelRes, next.icon, next.windowFlags, null, true); } if (DEBUG_SWITCH) Slog.v(TAG, "Restarting: " + next); } startSpecificActivityLocked(next, true, true);//启动Activity } return true; }
通过上面注释中的分析,在判断Activity进程之后,就会通过startSpecificActivityLocked()方法来启动Activity,我们继续看
private final void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { // Is this activity's application already running? ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid); if (r.launchTime == 0) { r.launchTime = SystemClock.uptimeMillis(); if (mInitialStartTime == 0) { mInitialStartTime = r.launchTime; } } else if (mInitialStartTime == 0) { mInitialStartTime = SystemClock.uptimeMillis(); } if (app != null && app.thread != null) {//Activity所在进程判断,进程存在时,直接启动Activity try { app.addPackage(r.info.packageName); realStartActivityLocked(r, app, andResume, checkConfig);//核心代码 return; } catch (RemoteException e) { Slog.w(TAG, "Exception when starting activity " + r.intent.getComponent().flattenToShortString(), e); } // If a dead object exception was thrown -- fall through to // restart the application. } mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false); }
在startSpecificActivityLocked()方法中也对Activity的进程是否存在做了判断,当进程存在时直接调用realStartActivityLocked()方法启动Activity;当Activity的进程不存在时,就会调用AMS的startProcessLocked()方法创建进程,这里其实是Activity的另一种启动流程,从Laucher启动,只有从Launcher启动才会没有进程,这里先不做深度分析,后续我们针对Activity的Launcher启动再写一篇博文。下面让我们继续看realStartActivityLocked()方法:
final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app, boolean andResume, boolean checkConfig) throws RemoteException { ....... app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken, System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration), r.compat, r.icicle, results, newIntents, !andResume, mService.isNextTransitionForward(), profileFile, profileFd, profileAutoStop); ...... return true; }
这里主要通过调用app.thread.scheduleLaunchActivity(…)方法实现了跨进程通信,这里主要实现了流程图中的第二次Binder跨进程通信。通过Binder跨进程通信调用了ApplicationThread中的scheduleLaunchActivity(…)方法,具体Binder怎么跨进程通信的,我已写过文章 Android跨进程通信方式(IPC)解析,想了解的同学,可以点击看看。下面我们继续来看看ApplicationThread中的scheduleLaunchActivity方法:
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident, ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo, Bundle state, ListpendingResults, List pendingNewIntents, boolean notResumed, boolean isForward, String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) { ActivityClientRecord r = new ActivityClientRecord(); ...... queueOrSendMessage(H.LAUNCH_ACTIVITY, r); } public void handleMessage(Message msg) { if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what)); switch (msg.what) { case LAUNCH_ACTIVITY: { Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart"); ActivityClientRecord r = (ActivityClientRecord)msg.obj; r.packageInfo = getPackageInfoNoCheck( r.activityInfo.applicationInfo, r.compatInfo); handleLaunchActivity(r, null);//核心代码 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); } break; ....... } }
由上易知,通过Handler消息循环机制,从而执行handleLaunchActivity()方法,我们继续来看此方法
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) { ....... Activity a = performLaunchActivity(r, customIntent); ...... } private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) { // System.out.println("##### [" + System.currentTimeMillis() + "] ActivityThread.performLaunchActivity(" + r + ")"); ActivityInfo aInfo = r.activityInfo; if (r.packageInfo == null) { r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo, Context.CONTEXT_INCLUDE_CODE); } ComponentName component = r.intent.getComponent(); if (component == null) { component = r.intent.resolveActivity( mInitialApplication.getPackageManager()); r.intent.setComponent(component); } if (r.activityInfo.targetActivity != null) { component = new ComponentName(r.activityInfo.packageName, r.activityInfo.targetActivity); } Activity activity = null; try { //1.核心代码 java.lang.ClassLoader cl = r.packageInfo.getClassLoader(); activity = mInstrumentation.newActivity( cl, component.getClassName(), r.intent); StrictMode.incrementExpectedActivityCount(activity.getClass()); r.intent.setExtrasClassLoader(cl); if (r.state != null) { r.state.setClassLoader(cl); } } catch (Exception e) { if (!mInstrumentation.onException(activity, e)) { throw new RuntimeException( "Unable to instantiate activity " + component + ": " + e.toString(), e); } } try { Application app = r.packageInfo.makeApplication(false, mInstrumentation); if (localLOGV) Slog.v(TAG, "Performing launch of " + r); if (localLOGV) Slog.v( TAG, r + ": app=" + app + ", appName=" + app.getPackageName() + ", pkg=" + r.packageInfo.getPackageName() + ", comp=" + r.intent.getComponent().toShortString() + ", dir=" + r.packageInfo.getAppDir()); if (activity != null) { ContextImpl appContext = new ContextImpl(); appContext.init(r.packageInfo, r.token, this); appContext.setOuterContext(activity); CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager()); Configuration config = new Configuration(mCompatConfiguration); if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity " + r.activityInfo.name + " with config " + config); //2.核心代码 activity.attach(appContext, this, getInstrumentation(), r.token, r.ident, app, r.intent, r.activityInfo, title, r.parent, r.embeddedID, r.lastNonConfigurationInstances, config); if (customIntent != null) { activity.mIntent = customIntent; } r.lastNonConfigurationInstances = null; activity.mStartedActivity = false; int theme = r.activityInfo.getThemeResource(); if (theme != 0) { activity.setTheme(theme); } activity.mCalled = false; //3.核心代码 mInstrumentation.callActivityOnCreate(activity, r.state); if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onCreate()"); } r.activity = activity; r.stopped = true; if (!r.activity.mFinished) { activity.performStart(); r.stopped = false; } if (!r.activity.mFinished) { if (r.state != null) { mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state); } } if (!r.activity.mFinished) { activity.mCalled = false; mInstrumentation.callActivityOnPostCreate(activity, r.state); if (!activity.mCalled) { throw new SuperNotCalledException( "Activity " + r.intent.getComponent().toShortString() + " did not call through to super.onPostCreate()"); } } } r.paused = true; mActivities.put(r.token, r); } catch (SuperNotCalledException e) { throw e; } catch (Exception e) { if (!mInstrumentation.onException(activity, e)) { throw new RuntimeException( "Unable to start activity " + component + ": " + e.toString(), e); } } return activity; }
注释1处,通过mInstrumentation.newActivity()方法对Activity进行初始化
public Activity newActivity(ClassLoader cl, String className, Intent intent) throws InstantiationException, IllegalAccessException, ClassNotFoundException { return (Activity)cl.loadClass(className).newInstance(); }
由上我们知道,主要通过反射机制实现Activity的初始化。再来看注释2,调用了Activity.attach(…)方法
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config) { attach(context, aThread, instr, token, 0, application, intent, info, title, parent, id, lastNonConfigurationInstances, config); } final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token, int ident, Application application, Intent intent, ActivityInfo info, CharSequence title, Activity parent, String id, NonConfigurationInstances lastNonConfigurationInstances, Configuration config) { attachBaseContext(context); mFragments.attachActivity(this); mWindow = PolicyManager.makeNewWindow(this); mWindow.setCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); } if (info.uiOptions != 0) { mWindow.setUiOptions(info.uiOptions); } mUiThread = Thread.currentThread(); mMainThread = aThread; mInstrumentation = instr; mToken = token; mIdent = ident; mApplication = application; mIntent = intent; mComponent = intent.getComponent(); mActivityInfo = info; mTitle = title; mParent = parent; mEmbeddedID = id; mLastNonConfigurationInstances = lastNonConfigurationInstances; mWindow.setWindowManager(null, mToken, mComponent.flattenToString(), (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0); if (mParent != null) { mWindow.setContainer(mParent.getWindow()); } mWindowManager = mWindow.getWindowManager(); mCurrentConfig = config; }
此方法主要就是对Activity进行了初始化,初始化了许多的属性,具体如上。我们再看注释3,方法mInstrumentation.callActivityOnCreate(activity, r.state),我们也来看看源码
public void callActivityOnCreate(Activity activity, Bundle icicle) { if (mWaitingActivities != null) { synchronized (mSync) { final int N = mWaitingActivities.size(); for (int i=0; i其实,主要也就是调用了Activity的OnCreate()方法,我们继续来看看
final void performCreate(Bundle icicle) { onCreate(icicle); mVisibleFromClient = !mWindow.getWindowStyle().getBoolean( com.android.internal.R.styleable.Window_windowNoDisplay, false); mFragments.dispatchActivityCreated(); }的确如此,最后调用了Activity的OnCreate方法,从而就启动了Activity。好了,到这里,Activity的启动流程就说完了。
注:源码采用android-4.1.1_r1版本,建议下载源码然后自己走一遍流程,这样更能加深理解。