源码理解:Activity启动流程及一些细节

本文将分析activity的启动流程,把握主流程和一些疑难点及回调的触发时机。

源码分析

该部分内容较长,会梳理流程并分析部分重点函数,读者可选择阅读,也可直接跳至总结部分

无论何种形式的startActivity,最终都会调用到startActivityForResult,该函数有三个参数需要理解一下:
intent即将要启动的目标intent
requestCode如果该值>0则该值将会在下一个activity启动后的onActivityResult返回获得
bundle可为null为配置参数。

public void startActivityForResult(Intent intent, int requestCode, @Nullable Bundle options) {
        if (mParent == null) {//没有parent的情况
            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) {
                // 这里用来作为下一个activity的返回标记
                mStartedActivity = true;
            }

            final View decor = mWindow != null ? mWindow.peekDecorView() : null;
            if (decor != null) {
                decor.cancelPendingInputEvents();//用来取消输入事件传递,内部主要取消了onclick和longPress的回调
            }
            // TODO Consider clearing/flushing other event sources and events for child windows.
        } else {//有parent的情况,需要遍历子activity
            if (options != null) {
                mParent.startActivityFromChild(this, intent, requestCode, options);
            } else {
                mParent.startActivityFromChild(this, intent, requestCode);
            }
        }
        if (options != null && !isTopOfTask()) {//大部分情况不用考虑
            mActivityTransitionState.startExitOutTransition(this, options);
        }
    }

通过上述代码,我们不难看出,启动activity主要分为两个分支,判断条件就是mParent是否为null,那么mParent到底是什么,何时赋值的呢?我为读者梳理了activity源码并找出了这个对象的来由,首先在activity创建后回调onCreate前会先触发attach这个方法,该方法会给mParent赋值
源码理解:Activity启动流程及一些细节_第1张图片
该方法是在ActivityThread里performLaunchActivity调用

activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.voiceInteractor);

再继续跟踪会发现LocalActivityManager的moveToState是调用源头

r.activity = mActivityThread.startActivityNow(
                    mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance);

而LocalActivityManager的mParent是在构造时传入的,创建LocalActivityManager的是AcivityGroup

public LocalActivityManager(Activity parent, boolean singleMode) {
        mActivityThread = ActivityThread.currentActivityThread();
        mParent = parent;
        mSingleMode = singleMode;
    }
    
public ActivityGroup(boolean singleActivityMode) {
        mLocalActivityManager = new LocalActivityManager(this, singleActivityMode);
    }

到这里我们就可以得出结论了,ActivityGroup创建后在其内部启动activity才会有mParent,其他情况mParent是null,而ActivityGroup是解决一个界面内可以存在多个activity问题提供的方案,后来已经被Fragment取代。
所以回到我们startActivityForResult的分析中,mParent在没有ActivityGroup的情况下都是null,我们基本不用考虑,我们接着分析不存在mParent的流程;

execStartActivity
(ActivityManagerService)startActivity
startActivityAsUser
(ActivityStackSupervisor)startActivityMayWait
startActivityLocked
startActivityUncheckedLocked

startActivityMayWait:这个函数先会有Binder的一系列UID/PID检查,检测当前包名和进程名,以及是否已存在重量级操作;

startActivityLocked:这里简言之就是各种check,最后一步以前先启动PendingActivity;

startActivityUncheckedLocked:首先确定是否需要出现在后台任务栈,然后通过传入的intent确定启动模式,当代码intent和manifest冲突时,manifest优先,以下是源码解释

// We have a conflict between the Intent and the Activity manifest, manifest wins.

根据确定的flag及caller的属性来决定是否要开启新的task,和是否要清除已存在activity上面的activity,或者栈顶已经是将启动的activity,这里将会分为两种情况:注意该方法执行完就将返回值返回了,将执行startActivityAsUser后面的函数检查执行结果:

public static void checkStartActivityResult(int res, Object intent) {
        if (res >= ActivityManager.START_SUCCESS) {
            return;
        }
        switch (res) {
            case ActivityManager.START_INTENT_NOT_RESOLVED:
            case ActivityManager.START_CLASS_NOT_FOUND:
                if (intent instanceof Intent && ((Intent)intent).getComponent() != null)
                    throw new ActivityNotFoundException(
                            "Unable to find explicit activity class "
                            + ((Intent)intent).getComponent().toShortString()
                            + "; have you declared this activity in your AndroidManifest.xml?");
                throw new ActivityNotFoundException(
                        "No Activity found to handle " + intent);
            case ActivityManager.START_PERMISSION_DENIED:
                throw new SecurityException("Not allowed to start activity "
                        + intent);
            case ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT:
                throw new AndroidRuntimeException(
                        "FORWARD_RESULT_FLAG used while also requesting a result");
            case ActivityManager.START_NOT_ACTIVITY:
                throw new IllegalArgumentException(
                        "PendingIntent is not an activity");
            case ActivityManager.START_NOT_VOICE_COMPATIBLE:
                throw new SecurityException(
                        "Starting under voice control not allowed for: " + intent);
            default:
                throw new AndroidRuntimeException("Unknown error code "
                        + res + " when starting " + intent);
        }
    }

在这里我们能看见一些常见的错误,如ActivityNotFoundException have you declared this activity in your AndroidManifest.xml?这就是没有在manifest里定义activity的错误;

第一种正常启动

standard启动模式,将执行startActivityLocked

targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);

该方法会将将启动的activity任务栈移动到顶部即前台栈,当将启动的activity和当前activity不在同一进程或者要启动新的栈时,会启动一个空白的preview window,如果是第一个topActivity就不需要动画,最后将执行resume操作;

(ActivityStackSupervisor)resumeTopActivitiesLocked
(ActivityStack)resumeTopActivityLocked
(ActivityStack)resumeTopActivityInnerLocked
(ActivityThread)handlePauseActivity
(ActivityThread)performPauseActivity
(ActivityStackSupervisor)startSpecificActivityLocked(next, true, true)
(ActivityThread)scheduleLaunchActivity
(ActivityThread)handleLaunchActivity
(ActivityThread)performLaunchActivity
(ActivityThread)handleResumeActivity

resumeTopActivitiesLocked:这里有一个注意点,该函数的尾部会执行两次;

resumeTopActivityLocked,第一次是目标栈activity即将要启动的,第二次是前台栈activity,这里也就解释了为什么A使用singleInstance模式,启动其他Bactivity之后再启动回来,B先destroy后又重新create的问题,handleLaunchActivity函数会进一步解释,这个activity如果是非关闭的但不是前台的activity需要onPause;

resumeTopActivityInnerLocked:会去找当前栈顶的activity,如果没有则会启动桌面launcher,检查所有的paused activity有没有完成,先将当前activity执行pause操作再resume目标activity,注意点从这个函数的源码也可以看出onActivityResult和onNewIntent的触发都先于onResume;

performPauseActivity:这里有一个注意点,如果不是finishActivity且targetSdk版本低于3.1才会触发onSaveInstance,我们从这个函数里也可以发现onSaveInstance触发先于onPause;

startSpecificActivityLocked:这个函数后两个参数表示是否需要resume和checkConfig后面启动流程会有用到;

handleLaunchActivity:这里我们也可以看出onConfigurationChange检测和触发要先于activity创建;

performLaunchActivity:用ClassLoader的newInstance来创建activity实例,执行makeApplication创建application和应用context触发applicaiton的onCreate,然后为activity创建context,调用activity.attach,为activity设置主题,触发onCreate,触发onRestoreInstanceState;

handleResumeActivity:首先关闭强制GC,这个GC是不能小于5S间隔的,而且会阻塞MainLooper,然后会按符合的条件依次执行如下代码:

				if (r.pendingIntents != null) {
                    deliverNewIntents(r, r.pendingIntents);//这里面会执行onNewIntent
                    r.pendingIntents = null;
                }
                if (r.pendingResults != null) {
                    deliverResults(r, r.pendingResults);/这里面会执行onActivityResult并传递给fragment
                    r.pendingResults = null;
                }
                r.activity.performResume();//后面详述

从以上代码我们可以看出,如果有pendingIntent,且有pendingResults会先执行onNewIntent再onActivityResult,接着我们分析一下performResume方法:

	final void performResume() {
        performRestart();//处理restart和start流程
		···省略
        mCalled = false;
        mInstrumentation.callActivityOnResume(this);//回调onResume
        ···省略
        mFragments.dispatchResume();//给fragment传递onResume
        ···省略
        onPostResume();//回调window的onActive
        ···省略
    }
    
   	final void performRestart() {
   		···省略
       if (mStopped) {//这个标记位在onStop回调会置为true
            ···省略
            mInstrumentation.callActivityOnRestart(this);//回调onReStart
	        ···省略
            performStart();//处理onStart流程
        }
    }

	final void performStart() {
        ···省略
        mInstrumentation.callActivityOnStart(this);//回调onStart
        ···省略
        mFragments.dispatchStart();//给fragment传递onStart
        ···省略
        mActivityTransitionState.enterReady(this);//后面详述
    }

	public void enterReady(Activity activity) {
        ···省略
        if (mEnterActivityOptions.isReturning()) {
            restoreExitedViews();//执行decorView的requesLayout
            activity.getWindow().getDecorView().setVisibility(View.VISIBLE);//使decorView可见
        }
        ···省略
    }
   

如上,为resume流程的主要几个步骤,另外如果activity不实现super.onResume(其他生命周期回调相同)的话会收到一个SuperNotCalledException。

通过上面代码流程分析我总结了以下关键点:

  1. 执行顺序:onReStart-onStart-onStart(fragment)-onResume-onResume(fragment)-onActive(window)
  2. performRestart函数里有一个mStopped标记位,它只有在onStop里被置为true的,也就是说如果activity没有执行过onStop那么onReStart和onStart均不会执行!
  3. activity和fragment的onStart都处理完后,会执行decorView的requesLayout并使其可见,也就是此时界面内容才是可见的;
  4. activity和fragment的onResume都处理完后,window才会active此时才可以处理触摸事件。

第二种singleTop、singleTask、singleInstance启动模式

之后将会执行deliverNewIntentLocked

if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0
                            || launchSingleInstance || launchSingleTask) {
 ActivityRecord top = intentActivity.task.performClearTaskLocked(r, launchFlags);
                        if (top != null) {
                            if (top.frontOfTask) {
                                top.task.setIntent(r);
                            }
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
                                    r, top.task);
                            top.deliverNewIntentLocked(callingUid, r.intent);
                        }
                        ······//省略
                    } else if (r.realActivity.equals(intentActivity.task.realActivity)) {
                        if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)
                                && intentActivity.realActivity.equals(r.realActivity)) {
                            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
                                    intentActivity.task);
                            if (intentActivity.frontOfTask) {
                                intentActivity.task.setIntent(r);
                            }
                            intentActivity.deliverNewIntentLocked(callingUid, r.intent);
                        }

onNewIntent执行完之后,此时会将栈顶的activity进行resume操作resumeTopActivityLocked这里会依次执行onReStart、onStart、onResume流程和之前正常启动类似,不做赘述;

总结

  1. startActivity最终会调用startActivityForResult,必须要requestCode>=0才会触发onActivityResult;
  2. Activity内部的mParent是ActivityGroup对象,现已被fragment代替其功能;
  3. 当intent内的启动模式flag和manifest注明的launchMode冲突时,manifest优先;
  4. 只有第一次启动activity(destroy过)才会触发onCreate,其他情况为onReStart;
  5. 当将启动的activity和当前activity不在同一进程或者要启动新的栈时,会启动一个空白的preview window;
  6. A使用singleInstance模式,启动其他Bactivity之后再启动回来,B先destroy后又重新create的问题,handleLaunchActivity函数会进一步解释,这个activity如果是非关闭的但不是前台的activity需要onPause;
  7. onActivityResult和onNewIntent的触发都先于onResume;
  8. 如果不是finishActivity且targetSdk版本低于3.1才会触发onSaveInstance(这里好像实际不是这样,后续再验证一下),onSaveInstance触发先于onPause;
  9. activity对象由ClassLoader的newInstance创建最早,然后创建application对象和其context再调用applicaiton的onCreate,再为activity创建context,调用activity.attach,为activity设置主题,触发onCreate,触发onRestoreInstanceState;
  10. 执行onStart之前,首先关闭强制GC,这个GC与上一次GC不能小于5S间隔的,而且会阻塞MainLooper,个人理解是关闭GC避免创建流程问题;
  11. 如果activity不实现super.onResume(其他生命周期回调相同)的话会收到一个SuperNotCalledException。
  12. performRestart函数里有一个mStopped标记位,它只有在onStop里被置为true的,也就是说如果activity没有执行过onStop那么onReStart和onStart均不会执行!
  13. activity和fragment的onStart都处理完后,会执行decorView的requesLayout并使其可见,也就是此时界面内容才是可见的;
  14. activity和fragment的onResume都处理完后,window才会active此时才可以处理触摸事件。

你可能感兴趣的:(android-进阶)