浅析 android 应用界面的展现流程(一)周期函数

“做了那么久的 Android APP 开发(从上学期间到目前为止间断的做了也有1年多了,还有一年多在玩 SSH、VC),也见过了那么多形形色色的界面设计,也做过不少 UI 上的需求,但仍然对 Android 界面的展现流程没有一个系统的认知,说来也是愧对自己导师和leader了。” 想来想去,这就算是这一年多安卓开发的忏悔之一了。

本系列文章将从 Activity 的使用出发,逐级分析一个 Android app 从启动到绘制布局再到展现给用户界面的总体逻辑,贯穿 目标进程、ActivityManagerService、WindowManagerService、Surfaceflinger,本系列文章将针对 Android 4.4 的源码进行讨论。

1. 引言 - Activity

(罗升阳罗老师的博客早已把UI相关的2.2的源码分析透彻,但个人认为其覆盖的点过于细致 - 这也是他的博客能做成优秀书籍的原因,作为读者在看的时候有的地方会觉得偏离主线反而忘了他在说什么,本文争取只对与主线相关的点做分析,让读者老爷们力争最短时间内把握好一条主线)

Activity 是展现给我们的可以称之为界面的组件,是最为常用的组件,也是用户UI的核心组件。如下代码为最为简单的一个界面类实现(由于本文不是讲如何开发的,有关基本布局、控件及其属性、周期函数等概念请移步 Google Android 官网):


public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

以及布局文件 activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <TextView
        android:text="Hello World"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>

配好 manifest 文件编译运行后会出现一个包含一行文字 “Hello World” 的界面!

说实话,现在看着这个 Hello World 我仍然感到激动,因为 Android 就这样让我这样的开发者写这么点代码就在手机上展现出画面。

看着这个界面我们肯定会有这样一系列的问题


1. onCreate 是什么?谁调用它的?什么时候调用的?(startActivity 如何启动界面以及周期函数的调用时机)
2. 我们用 setContentView 设置了布局,那么这个布局是如何添加到这个总界面里的?(WindowManager)
3. Android 怎么知道我们要画多大的布局多大的控件?(测量过程)
4. Android 是如何依赖这些布局文件去绘制的?(draw)
5. 这些绘制为何会显示在屏幕上?(Surfaceflinger)

我们就针对上面最简单的 HelloWorld 一个个的来说,如果有需要讲的分支内容,会以外链形式出现,这算是若干篇文章拼成的短篇小说。

2. 周期函数

如果我们想启动如上那个界面,一般来说用 Context.startActivity 方法即可,Context 可以是 Application、Activity、Service,可以是外部进程甚至外部应用启动,也可以是进程内启动,在这里我们只看一种途径就是进程内启动 Activity(进程外就是多了启动进程一步,具体可以参考通过 startService 在新进程中启动服务的流程)。Activity 比较重要的周期函数有 onCreate、onResume、onStart、onPause、onStop、onDestroy,本节我们来看与界面展现相关的 onCreate、onStart、onResume 周期函数的执行时机。

startActivitiy 从应用程序端到 AMS 的流程基本与《通过 startService 在新进程中启动服务的流程(一)》相似,周期函数的调用也是,如图 2.1 所示为从 Activity.startActivity 到 onResume 执行的过程(非新进程):

<center>

startActivity_onCreate.jpg

图 2.1 从 Activity.startActivity 到 onResume 执行的过程(Android 4.4)</center>

2.1 从 startActivity 到 Binder 调用(步骤1-步骤5 )

步骤2:startActivity 最终总是会执行 startActivityForResult,
步骤3:Instrumentation 是 Android 测试框架,如果应用程序中没有自定义的 Instrumentation,那么就会用默认的 android.app.Instrumentation,引用一句注释吧:

Base class for implementing application instrumentation code. When running with instrumentation turned on, this class will be instantiated for you before any of the application code, allowing you to monitor all of the interaction the system has with the application. An Instrumentation implementation is described to the system through an AndroidManifest.xml's <instrumentation> tag.

有关测试的相关内容本人也不太熟悉,大家可以查看这篇文章
步骤4:在 Instrumentation.exeStartActivity 中:

int result = ActivityManagerNative.getDefault()
            .startActivity(whoThread, who.getBasePackageName(), intent,
                    intent.resolveTypeIfNeeded(who.getContentResolver()),
                    token, target != null ? target.mEmbeddedID : null,
                    requestCode, 0, null, null, options);

ActivityManagerNative.getDefault() 拿到的是其实是一个 IActivityManager Binder 对象了:

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        IBinder b = ServiceManager.getService("activity");
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        IActivityManager am = asInterface(b);
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};

class Singleton<T> 可以说是一个小而稳定的单例框架:

public abstract class Singleton<T> {
    private T mInstance;

    protected abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}

这当然完全都可以拿到自己的项目工程里用了,不过在源码里只有 ActivityManagerNative 和 StrictMode 用到了 - -。
关于 ServiceManager.getService("activity") 的流程请参考《浅谈 SystemServer》。ActivityManagerNative 实际就是服务端的 Binder 实现基类了,ActivityManagerService 即继承于 ActivityManagerNative 的,关于 Binder 实现的相关内容还请参考罗老师的博客了。

2.2 ActivityManagerService.startActivity(步骤6 - 步骤13)

在 ActivityManagerService 中,实际去管理、启动 Activity 的管理类是 ActivityStackSupervisor(仅限 Android 4.4),在 Android 4.4 上靠这个类将 Activity 相关的管理功能从 AMS 中剥离了出来(AMS 舒了一口气,表情轻松),ActivityManagerService.startActivity 会执行到 ActivityStackSupervisor.startActivityMayWait() 方法,该方法在解析完目标 Intent 后,执行 startActivityLocked(),由于源码中针对 requestCode、FLAG 有繁多的情况判断,我们这里预备最简单的情况即 requetCode < 0 并 FLAG = 0:

final int startActivityLocked(IApplicationThread caller,
        Intent intent, String resolvedType, ActivityInfo aInfo, IBinder resultTo,
        String resultWho, int requestCode,
        int callingPid, int callingUid, String callingPackage, int startFlags, Bundle options,
        boolean componentSpecified, ActivityRecord[] outActivity) {
    int err = ActivityManager.START_SUCCESS;

    ProcessRecord callerApp = null;
    if (caller != null) {
1.      callerApp = mService.getRecordForAppLocked(caller);
        if (callerApp != null) {
            callingPid = callerApp.pid;
            callingUid = callerApp.info.uid;
        } else {
            ......
            err = ActivityManager.START_PERMISSION_DENIED;
        }
    }
    ......
    ActivityRecord sourceRecord = null;
    ActivityRecord resultRecord = null;
    if (resultTo != null) {
        sourceRecord = isInAnyStackLocked(resultTo);
        ......
    }
    ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;

    int launchFlags = intent.getFlags();
    ......

2.  ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
            intent, resolvedType, aInfo, mService.mConfiguration,
            resultRecord, resultWho, requestCode, componentSpecified, this);
    ......

3.  mService.doPendingActivityLaunchesLocked(false);

4.  err = startActivityUncheckedLocked(r, sourceRecord, startFlags, true, options);

    if (allPausedActivitiesComplete()) {
        dismissKeyguard();
    }
    return err;
}

第一步是判断执行 startActivity 的进程是否还在,如果不在则不允许启动(这点也就是为什么不能在独立进程伪造 Context 的缘故之一),传入的参数 resultTo 实际上是每一个启动的 Activity 在 WindowManagerService 中注册的 IApplicationToken,那么 sourceRecord 即执行者 Activity 对应的 ActivityRecord;
第二步是创建 ActivityRecord;
第三步会将 mPendingActivityLaunches 中的 Activity 启动完,即将该处理的 Activity 都处理掉,mPendingActivityLaunches 里均为即将要启动的 Activity;
第四步 startActivityUncheckedLocked:

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

    ......

    boolean addingToTask = false;
    boolean movedHome = false;
    TaskRecord reuseTask = null;
    ActivityStack targetStack;
    ......

    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) {
        ......
    } else if (sourceRecord != null) {
        TaskRecord sourceTask = sourceRecord.task;
        targetStack = sourceTask.stack;
        moveHomeStack(targetStack.isHomeStack());
        mWindowManager.moveTaskToTop(sourceTask.taskId);
        
        // 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(sourceTask, sourceRecord.thumbHolder, false);
        if (DEBUG_TASKS) Slog.v(TAG, "Starting new activity " + r
                + " in existing task " + r.task + " from source " + sourceRecord);

    } else {
        ......
    }
    ......
    targetStack.mLastPausedActivity = null;
    targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
    mService.setFocusedActivityLocked(r);
    return ActivityManager.START_SUCCESS;
}

在 FLAG=0 且 requestCode=0 的情况下,startActivityUncheckedLocked 的代码会被我们从 442 行精简到上面那么多。
targetStack 其实就是启动者所在的 ActivityStack,执行 ActivityStack.startActivityLocked:

final void startActivityLocked(ActivityRecord r, boolean newTask,
        boolean doResume, boolean keepCurTransition, Bundle options) {
    TaskRecord rTask = r.task;
    final int taskId = rTask.taskId;
    ......
    TaskRecord task = null;
    ......
    task = r.task;

    ......
1.  task.addActivityToTop(r);
2.  task.setFrontOfTask();

3.  r.putInHistory();
    if (!isHomeStack() || numActivities() > 0) {
        // We want to show the starting preview window if we are
        // switching to a new task, or the next activity's process is
        // not currently running.
        boolean showStartingIcon = newTask;
        ProcessRecord proc = r.app;
        if (proc == null) {
            proc = mService.mProcessNames.get(r.processName, r.info.applicationInfo.uid);
        }
        if (proc == null || proc.thread == null) {
            showStartingIcon = true;
        }
        if (DEBUG_TRANSITION) Slog.v(TAG,
                "Prepare open transition: starting " + r);
4.      if ((r.intent.getFlags()&Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0) {
            mWindowManager.prepareAppTransition(AppTransition.TRANSIT_NONE, keepCurTransition);
            mNoAnimActivities.add(r);
        } else {
            mWindowManager.prepareAppTransition(newTask
                    ? AppTransition.TRANSIT_TASK_OPEN
                    : AppTransition.TRANSIT_ACTIVITY_OPEN, keepCurTransition);
            mNoAnimActivities.remove(r);
        }
        r.updateOptionsLocked(options);
5.      mWindowManager.addAppToken(task.mActivities.indexOf(r),
                r.appToken, r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
                (r.info.flags & ActivityInfo.FLAG_SHOW_ON_LOCK_SCREEN) != 0, r.userId,
                r.info.configChanges);
        boolean doShow = true;
        ......
    } else {
        ......
    }
    ......

    if (doResume) {
6.      mStackSupervisor.resumeTopActivitiesLocked();
    }
}

第一步是将要启动的 Activity 加入到目标栈(TaskRecord)中,这里的栈即启动者 Activity 所在的栈(Task);
第二步是将该栈置为最前;
第三步是将该 Activity 所在的栈中的数目同步;
第四步是告诉 WMS 该 Activity 启动时是否有动画;
第五步在后面的文章中也有提到,就是添加 AppWindowToken 到 WMS 的 mTaskMap 映射中,key 为 IApplicationToken(ActivityRecord 构造函数中初始化的);
第六步 resumeTopActivitiesLocked:

boolean resumeTopActivitiesLocked(ActivityStack targetStack, ActivityRecord target,
        Bundle targetOptions) {
    if (targetStack == null) {
        targetStack = getFocusedStack();
    }
    boolean result = false;
    for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
        final ActivityStack stack = mStacks.get(stackNdx);
        if (isFrontStack(stack)) {
            if (stack == targetStack) {
                result = stack.resumeTopActivityLocked(target, targetOptions);
            } else {
                ......
            }
        }
    }
    return result;
}

转到 ActivityStack.resumeTopActivityLocked:

final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) { // prev=options=null

    ActivityRecord next = topRunningActivityLocked(null); // 要启动的 Activity

    final boolean userLeaving = mStackSupervisor.mUserLeaving;
    mStackSupervisor.mUserLeaving = false;

    ......
    next.delayedResume = false;

    // If the top activity is the resumed one, nothing to do.
    if (mResumedActivity == next && next.state == ActivityState.RESUMED &&
                mStackSupervisor.allResumedActivitiesComplete()) {
        ......
        return false;
    }
    ......
    // We need to start pausing the current activity so the top one
    // can be resumed...
    boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving);
    if (mResumedActivity != null) {
        pausing = true;
        startPausingLocked(userLeaving, false);
        if (DEBUG_STATES) Slog.d(TAG, "resumeTopActivityLocked: Pausing " + mResumedActivity);
    }
    if (pausing) {
        ......
        return true;
    }
    ......
}

在 ActivityStack 中有个重要的变量 mResumedActivity,即代表当前正在显示中的 Activity,在启动目标 Activity 之前我们要先把这个Activity 给 Pause 了,即执行 startPausingLocked,在上面的步骤中并没有将详细步骤标出来(因为线一交叉就很难看 - -),如图为 startPausingLocked() 的流程:
<center>

startActivity_pre_pause.jpg

图 2.2 startPausingLocked() 的流程(Android 4.4)</center>
具体的代码我这里就不贴了,一步步跟下去也都很简单。
可以看出在将当前显示中的 Activity 暂停后,又执行回了 resumeTopActivity,但这回就不会再走到 startPausingLocked 中了:

final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {
    ......
    if (next.app != null && next.app.thread != null) {
        ......
    } else {
        ......
        mStackSupervisor.startSpecificActivityLocked(next, true, true);
    }
    ......
    return true;
}

继续来看 resumeTopActivityLocked 剩下的代码(已经精简到令人发指了),虽然不想承认,但是到目前为止,我们创建的 ActivityRecord 对象的 app 字段还未赋过值,所以执行 ActivityStackSupervisor.startSpecificActivityLocked():

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, true);

    r.task.stack.setLaunchTime(r);

    if (app != null && app.thread != null) {
        try {
            if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0
                    || !"android".equals(r.info.packageName)) {
                // Don't add this if it is a platform component that is marked
                // to run in multiple processes, because this is actually
                // part of the framework so doesn't make sense to track as a
                // separate apk in the process.
                app.addPackage(r.info.packageName, mService.mProcessStats);
            }
1.          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.
    }

2.  mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
            "activity", r.intent.getComponent(), false, false, true);
}

第二步其实是在新进程中启动 Activity 才会执行的,这里说的是在既有进程内启动 Activity,也就说只执行第一步 realStartActivityLocked,这里基本跟启动 Service 时 realStartServiceLocked 几乎一样,大家可以参考《通过 startService 在新进程中启动服务的流程(二)》,只不过 realStartServiceLocked 时是调用 IApplicationThread.scheduleCreateService,这里是调用 IApplicationThread.scheduleLaunchActivity。

2.3 onCreate(步骤14 - 步骤19)

Binder 调用 scheduleLaunchActivity 实际调的是 ActivityThread.mAppThread.scheduleLaunchActivity,又用消息机制传到了 handleLaunchActivity,在这里正式开始 Activity 的周期函数:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ......

1.  Activity a = performLaunchActivity(r, customIntent);

    if (a != null) {
        r.createdConfig = new Configuration(mConfiguration);
        Bundle oldState = r.state;
2.      handleResumeActivity(r.token, false, r.isForward,
                !r.activity.mFinished && !r.startsNotResumed);

        ......
    } else {
        ......
    }
}

在这里值得一提的是,在 performLaunchActivity 中,不仅仅有 onCreate 的调用,在 onCreate 之前还会执行 attach 去对 Activity 的 Context 进行赋值以及做一些字段初始化工作(包括后面文章要讲的 WindowManager):

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ......

    ActivityInfo aInfo = r.activityInfo;
    if (r.packageInfo == null) {
        r.packageInfo = getPackageInfo(aInfo.applicationInfo, r.compatInfo,
                Context.CONTEXT_INCLUDE_CODE);
    }

    ComponentName component = r.intent.getComponent();
    ......

    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) {
        ......
    }

    try {
        Application app = r.packageInfo.makeApplication(false, mInstrumentation);
        ......
        if (activity != null) {
            ......
2.          activity.attach(appContext, this, getInstrumentation(), r.token,
                    r.ident, app, r.intent, r.activityInfo, title, r.parent,
                    r.embeddedID, r.lastNonConfigurationInstances, config);

            ......
3.          mInstrumentation.callActivityOnCreate(activity, r.state);
            ......
4.          if (!r.activity.mFinished) {
                activity.performStart();
                r.stopped = false;
            }
            if (!r.activity.mFinished) {
                if (r.state != null) {
5.                  mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
                }
            }
            ......
        }
        r.paused = true;

        mActivities.put(r.token, r);

    } catch (SuperNotCalledException e) {
        ......
    } catch (Exception e) {
        ......
    }

    return activity;
}

第一步创建指定的 Activity 对象,可以发现用的是 PackageInfo 的 Classloader,名字是 component.getClassName,那么我们如果将 PackageInfo 的 Classloader 换掉~可以实现一些高档的功能了;
第二步是attach,这个函数会在后面的文章中详细展开;
第三步即是 Activity.onCreate 的执行;
第四步即 Activity.onStart 的执行
第五步即 Activity.onRestoreInstanceState;

2.4 handleResumeActivity(步骤20 - 步骤30)

onRestart(刚启动的 Activity 不会执行)、onResume 会在 handleResumeActivity中执行完:

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
        boolean reallyResume) {
    // If we are getting ready to gc after going to the background, well
    // we are back active so skip it.
    unscheduleGcIdler();
1.  ActivityClientRecord r = performResumeActivity(token, clearHide);
    if (r != null) {
        final Activity a = r.activity;
        ......
2.      boolean willBeVisible = !a.mStartedActivity;
        if (!willBeVisible) {
            try {
                willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
                        a.getActivityToken());
            } catch (RemoteException e) {
            }
        }
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
3.          View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
            if (a.mVisibleFromClient) {
                a.mWindowAdded = true;
                wm.addView(decor, l);
            }

        } else if (!willBeVisible) {
            ......
        }

        // Get rid of anything left hanging around.
        cleanUpPendingRemoveWindows(r);

        // The window is now visible if it has been added, we are not
        // simply finishing, and we are not starting another activity.
4.      if (!r.activity.mFinished && willBeVisible
                && r.activity.mDecor != null && !r.hideForNow) {
            ......
            WindowManager.LayoutParams l = r.window.getAttributes();
            if ((l.softInputMode
                    & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
                    != forwardBit) {
                l.softInputMode = (l.softInputMode
                        & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
                        | forwardBit;
                if (r.activity.mVisibleFromClient) {
                    ViewManager wm = a.getWindowManager();
                    View decor = r.window.getDecorView();
                    wm.updateViewLayout(decor, l);
                }
            }
            r.activity.mVisibleFromServer = true;
            mNumVisibleActivities++;
            if (r.activity.mVisibleFromClient) {
                r.activity.makeVisible();
            }
        }

        ......

        // Tell the activity manager we have resumed.
        if (reallyResume) {
            try {
5.              ActivityManagerNative.getDefault().activityResumed(token);
            } catch (RemoteException ex) {
            }
        }

    } else {
        ......
    }
}

第一步其实就是图中已经标注的三个周期函数的执行过程,实际执行的是 Activity.performResume();
第二步中,mStartedActivity 若为 true,意思就是指示该 Activity 是已经启动了的,还没 finish,但又没添加到 WMS 中,可能启动了其他 Activity,第一次执行的 Activity 在这里肯定为 false,那么 willBeVisible 肯定为 true;
第三步创建 DecorView 并添加到 WindowManager 中,这一步会在下一篇文章中展开说明;
第四步,WMS 已经添加了该 Activity 的窗口,我们将会把该 Activity 置为可见;
第五步通知 AMS 这个 Activity 已经 resume 了。

我们将第一步展开来看:

final void performResume() {
    performRestart(); // onRestart
    
    mFragments.execPendingActions();
    
    mLastNonConfigurationInstances = null;
    
    mCalled = false; // 
    // mResumed is set by the instrumentation
    mInstrumentation.callActivityOnResume(this); // onResume
    if (!mCalled) {
        throw new SuperNotCalledException(
            "Activity " + mComponent.toShortString() +
            " did not call through to super.onResume()");
    }

    // Now really resume, and install the current status bar and menu.
    mCalled = false;
    
    mFragments.dispatchResume();
    mFragments.execPendingActions();
    
    onPostResume();
    if (!mCalled) {
        throw new SuperNotCalledException(
            "Activity " + mComponent.toShortString() +
            " did not call through to super.onPostResume()");
    }
}

这里我们看到一个叫 mCalled 的 boolean 值,它是当我们重写了必须调父类方法的周期函数时,会根据它来判断调没调父类,若没有,则抛出一个 SuperNotCalledException 异常。
展开 performRestart():

final void performRestart() {
    mFragments.noteStateNotSaved();

    if (mStopped) {
        mStopped = false;
        if (mToken != null && mParent == null) {
            WindowManagerGlobal.getInstance().setStoppedState(mToken, false);
        }

        synchronized (mManagedCursors) {
            final int N = mManagedCursors.size();
            for (int i=0; i<N; i++) {
                ManagedCursor mc = mManagedCursors.get(i);
                if (mc.mReleased || mc.mUpdated) {
                    if (!mc.mCursor.requery()) {
                        if (getApplicationInfo().targetSdkVersion
                                >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                            throw new IllegalStateException(
                                    "trying to requery an already closed cursor  "
                                    + mc.mCursor);
                        }
                    }
                    mc.mReleased = false;
                    mc.mUpdated = false;
                }
            }
        }

        mCalled = false;
        mInstrumentation.callActivityOnRestart(this);
        if (!mCalled) {
            throw new SuperNotCalledException(
                "Activity " + mComponent.toShortString() +
                " did not call through to super.onRestart()");
        }
        performStart();
    }
}

可以发现只有当 mStopped 为 true 时,即从 stop 的状态恢复时才会执行 onRestart。
最后执行 mInstrumentation.callActivityOnResume:

public void callActivityOnResume(Activity activity) {
    activity.mResumed = true;
    activity.onResume();
    ......
}

执行 Activity.onResume()。

2.5 小结

本文主要分析了 startActivity 的大体过程(所谓大体,就是撇开了繁冗的条件判断,默认FLAG=0),将周期函数 onCreate、onStart、onResume 串起来,让大家能清晰的看到这三个周期函数的执行时机。下篇文章将开始对界面的展现流程进行分析,即 2.4 节提到的创建 DecorView,我们将看到什么是 DecorView 以及一个最简单 Activity 的具体布局情况。

标签: none

添加新评论