android activity window创建过程

/ android / 没有评论 / 528浏览

用到的代码文件

frameworks/base/core/java/:
android/app/ActivityThread.java
android/app/Activity.java
com/android/internal/policy/PhoneWindow.java
android/view/Window.java
android/app/Instrumentation.java

代码执行流程图

android activity window 查看原图

代称执行流程

下面的代码是以android N(api 24)为基础。

下面的log是当我从launcher中启动某一个应用的流程输出。

Activity的Window创建流程发生在activity 启动过程的performLaunchActivity()方法中。
当通过反射方式创建出指定的activity后,就会调用activity的attach方法。

下面是ActivityThread类中的performLaunchActivity()方法。

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

    /**
      * 发射方式创建activity
      */
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        StrictMode.incrementExpectedActivityCount(
                activity.getClass());
        r.intent.setExtrasClassLoader(cl);
        r.intent.prepareToEnterProcess();
        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 {
        ......

        if (activity != null) { // -> true
            Context appContext = 
              createBaseContextForActivity(r, activity);
            CharSequence title =
              r.activityInfo.loadLabel(appContext
                  .getPackageManager());
            Configuration config = 
              new Configuration(mCompatConfiguration);
            if (r.overrideConfig != null) { // -> true
                config.updateFrom(r.overrideConfig);
            }
            if (DEBUG_CONFIGURATION) Slog.v(TAG, 
                    "Launching activity "
                    + r.activityInfo.name + " with config "
                    + config);
            Window window = null;
            if (r.mPendingRemoveWindow != null 
                    && r.mPreserveWindow) { // -> false
                window = r.mPendingRemoveWindow;
                r.mPendingRemoveWindow = null;
                r.mPendingRemoveWindowManager = null;
            }
            /**
              * 进入这里开始创建window对象
              */
            activity.attach(appContext, this, 
                            getInstrumentation(), r.token,
                            r.ident, app, r.intent, r.activityInfo, 
                            title, r.parent,r.embeddedID,
                            r.lastNonConfigurationInstances, 
                            config,r.referrer, r.voiceInteractor, 
                            window);

            if (customIntent != null) { // -> false
                activity.mIntent = customIntent;
            }
            r.lastNonConfigurationInstances = null;
            activity.mStartedActivity = false;
            int theme = r.activityInfo.getThemeResource();
            if (theme != 0) { // -> true
                activity.setTheme(theme);
            }

            activity.mCalled = false;
            if (r.isPersistable()) { // -> false
                mInstrumentation.callActivityOnCreate(activity, 
                    r.state, r.persistentState);
            } else {
                /*
                 * 从这里开始调用onCreate()
                 */
                mInstrumentation.callActivityOnCreate(activity, 
                    r.state);
            }
            if (!activity.mCalled) {// -> false
                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) { // -> true
                /*
                 * 从这里开始调用onStart()
                 */
                activity.performStart();
                r.stopped = false;
            }
            if (!r.activity.mFinished) { // -> true
                if (r.isPersistable()) { // -> false
                    if (r.state != null 
                        || r.persistentState != null) {
                        mInstrumentation
                          .callActivityOnRestoreInstanceState(
                              activity, r.state,
                              r.persistentState);
                    }
                } else if (r.state != null) { // -> false
                    mInstrumentation
                        .callActivityOnRestoreInstanceState(
                              activity, r.state);
                }
            }
            if (!r.activity.mFinished) { // -> true
                activity.mCalled = false;
                if (r.isPersistable()) { // ->false
                    mInstrumentation
                        .callActivityOnPostCreate(
                            activity, r.state,
                            r.persistentState);
                } else {
                    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;
}

接下来调用Activity类中的attach方法,在attach方法中构建Window对象。

private Window mWindow;

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, String referrer, 
        IVoiceInteractor voiceInteractor,
        Window window) {
    log("method called attach()");
    //android.app.ContextImpl@e9cf2af
    log("context : "+context); 
    // android.app.ActivityThread@d1ed6bc
    log("aThread : "+aThread); 
    // android.app.Instrumentation@cf6e645
    log("instr : "+instr); 
    //android.os.BinderProxy@e4f2a89
    log("token : "+token); 
    //155521742
    log("ident : "+ident); 
    log("application : "+application);
    //com.jrdcom.filemanager
    //  .FileManagerApplication@eda6453
    log("intent : "+intent);
    // Intent { act=android.intent.action.MAIN 
    //          cat=[android.intent.
    //  category.LAUNCHER] flg=0x10200000 
    //  cmp=com.jrdcom.filemanager/
    //  .activity.FileBrowserActivity 
    //  bnds=[146,628][227,709] (has extras) }
    log("info : "+info);
    //ActivityInfo{66089ea 
    //com.jrdcom.filemanager.activity.FileBrowserActivity}
    log("title : "+title);//File manager
    log("parent : "+parent);//null
    log("id : "+id);//null
    log("lastNonConfigurationInstances : "
        +lastNonConfigurationInstances);//null
    log("config : "+config);
    //{1.0 ?mcc?mnc [en_US] ldltr sw320dp w320dp h545dp 240dpi 
    //nrml long port finger -keyb/v/h -nav/h s.4}
    log("referrer : "+referrer);//com.tct.launcher
    log("voiceInteractor : "+voiceInteractor);//null
    log("window : "+window);//null

    printClass("token",token); //android.os.BinderProxy
    // android.content.res.Configuration
    printClass("config",config); 

    attachBaseContext(context);

    mFragments.attachHost(null /*parent*/);

    /*
      * 核心在这里,构建Window对象。
      */
    mWindow = new PhoneWindow(this, window);
    mWindow.setWindowControllerCallback(this);
    mWindow.setCallback(this);
    mWindow.setOnWindowDismissedCallback(this);
    mWindow.getLayoutInflater().setPrivateFactory(this);
    if (info.softInputMode != WindowManager.LayoutParams.
            SOFT_INPUT_STATE_UNSPECIFIED) { // -> false
        mWindow.setSoftInputMode(info.softInputMode);
    }
    if (info.uiOptions != 0) { // ->false
        mWindow.setUiOptions(info.uiOptions);
    }
    mUiThread = Thread.currentThread();

    mMainThread = aThread;
    log("mUiThread : "+mUiThread);// Thread[main,5,main]
    // android.app.ActivityThread@d1ed6bc
    log("mMainThread : "+mMainThread);
    mInstrumentation = instr;
    mToken = token;
    mIdent = ident;
    mApplication = application;
    mIntent = intent;
    mReferrer = referrer;
    mComponent = intent.getComponent();
    mActivityInfo = info;
    mTitle = title;
    mParent = parent;
    mEmbeddedID = id;
    mLastNonConfigurationInstances = 
            lastNonConfigurationInstances;
    if (voiceInteractor != null) { // ->false
        if (lastNonConfigurationInstances != null) {
            mVoiceInteractor = 
                lastNonConfigurationInstances.voiceInteractor;
        } else {
            mVoiceInteractor = new VoiceInteractor(
                voiceInteractor, this, this,
                    Looper.myLooper());
        }
    }

    mWindow.setWindowManager((WindowManager)
        context.getSystemService(Context.WINDOW_SERVICE),
        mToken, mComponent.flattenToString(),
        (info.flags 
            & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
    if (mParent != null) { // -> false
        mWindow.setContainer(mParent.getWindow());
    }
    mWindowManager = mWindow.getWindowManager();
    mCurrentConfig = config;
}

当进入activity的生命周期onCreate()方法,开始调用setContentView()方法。
下面是Activity类中的setContentView方法。

public void setContentView(@LayoutRes int layoutResID) {
    /*
     * 这里的Window对象就是上面attach方法中创建的PhoneWindow对象
     */
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

下面是PhoneWindow类中的setContentView()方法。这个方法基本上就把我们一个activity的布局完全创建出来了。

/*
 * FEATURE_CONTENT_TRANSITIONS这个是一种过度动画,用它
 * 可以实现一些更华丽的界面切换过度效果。
 */
@Override
public void setContentView(int layoutResID) {
    log("method called setContentView()");
    // Note: FEATURE_CONTENT_TRANSITIONS may be set 
    // in the process of installing the window
    // decor, when theme attributes and the like are 
    // crystalized. Do not check the feature
    // before this happens.
    if (mContentParent == null) {
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        mContentParent.removeAllViews();
    }

    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        final Scene newScene = Scene
            .getSceneForLayout(mContentParent, 
                  layoutResID,getContext());
        transitionTo(newScene);
    } else {
        /*
         * 我们加载某个布局到viewgroup中去,很熟悉的感觉。
         */
        mLayoutInflater.inflate(layoutResID, 
            mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
    mContentParentExplicitlySet = true;
}

当Activity中的onCreate和onStart方法执行完后开始执行ActivityThread类中的handleResumeActivity()方法。

final void handleResumeActivity(IBinder token,
    boolean clearHide, boolean isForward, 
    boolean reallyResume, int seq, String reason) {
    ActivityClientRecord r = mActivities.get(token);
    if (!checkAndUpdateLifecycleSeq(seq, r, 
        "resumeActivity")) {
        return;
    }
    log("method called handleResumeActivity()");
    // If we are getting ready to gc after 
    // going to the background, well
    // we are back active so skip it.
    unscheduleGcIdler();
    mSomeActivitiesChanged = true;

    // TODO Push resumeArgs into the activity 
    // for consideration
    r = performResumeActivity(token, clearHide, reason);

    if (r != null) { // -> true
        log("r is not null");
        final Activity a = r.activity;

        if (localLOGV) Slog.v(
            TAG, "Resume " + r + " started activity: " 
            + a.mStartedActivity + ", hideForNow: " 
            + r.hideForNow
            + ", finished: " + a.mFinished);

        final int forwardBit = isForward ?
                WindowManager.LayoutParams
                    .SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

        // If the window hasn't yet been added to the 
        // window manager, and this guy didn't finish 
        // itself or start another activity,
        // then go ahead and add the window.
        boolean willBeVisible = !a.mStartedActivity;
        if (!willBeVisible) {
            try {
                willBeVisible = ActivityManagerNative
                    .getDefault().willActivityBeVisible(
                        a.getActivityToken());
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
        // -> true
        if (r.window == null && !a.mFinished && willBeVisible) { 
            r.window = r.activity.getWindow();
            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 (r.mPreserveWindow) { // -> false
                a.mWindowAdded = true;
                r.mPreserveWindow = false;
                // Normally the ViewRoot sets up 
                // callbacks with the Activity
                // in addView->ViewRootImpl#setView. 
                // If we are instead reusing
                // the decor view we have to notify 
                // the view root that the
                // callbacks may have changed.
                ViewRootImpl impl = decor.getViewRootImpl();
                if (impl != null) {
                    impl.notifyChildRebuilt();
                }
            }
            // -> true
            if (a.mVisibleFromClient && !a.mWindowAdded) { 
                a.mWindowAdded = true;
                wm.addView(decor, l);
            }

        // If the window has already been added, but 
        // during resume we started another activity, 
        // then don't yet make the
        // window visible.
        } else if (!willBeVisible) { // -> false
            if (localLOGV) Slog.v(
                TAG, "Launch " + r 
                + " mStartedActivity set");
            r.hideForNow = true;
        }

        // Get rid of anything left hanging around.
        cleanUpPendingRemoveWindows(r, false /* force */);

        // The window is now visible if it has 
        // been added, we are not
        // simply finishing, and we are not starting
        // another activity.
        if (!r.activity.mFinished && willBeVisible
                && r.activity.mDecor != null 
                && !r.hideForNow) { // -> true
            if (r.newConfig != null) { // -> false
                performConfigurationChangedForActivity(r, 
                    r.newConfig, REPORT_TO_ACTIVITY);
                if (DEBUG_CONFIGURATION) 
                    Slog.v(TAG, "Resuming activity "
                        + r.activityInfo.name 
                        + " with newConfig " 
                        + r.activity.mCurrentConfig);
                r.newConfig = null;
            }
            if (localLOGV) 
                Slog.v(TAG, "Resuming " + r 
                    + " with isForward="
                    + isForward);
            WindowManager.LayoutParams l = 
                r.window.getAttributes();
            if ((l.softInputMode
                & WindowManager.LayoutParams
                    .SOFT_INPUT_IS_FORWARD_NAVIGATION)
                != forwardBit) { // -> false
                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++;
            // ->true
            if (r.activity.mVisibleFromClient) { 
                /**
                  *这里是重点。
                  */
                r.activity.makeVisible();
            }
        }

        if (!r.onlyLocalRequest) { // -> true
            r.nextIdle = mNewActivities;
            mNewActivities = r;
            if (localLOGV) Slog.v(
                TAG, "Scheduling idle handler for " + r);
            Looper.myQueue().addIdleHandler(new Idler());
        }
        r.onlyLocalRequest = false;

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

    } else {
        // If an exception was thrown when trying 
        // to resume, then
        // just end this activity.
        try {
            ActivityManagerNative.getDefault()
                .finishActivity(token, 
                  Activity.RESULT_CANCELED, null,
                  Activity.DONT_FINISH_TASK_WITH_ACTIVITY);
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
}

在 makeVisible 方法中,DecorView 才真正的完成了显示过程,到这里 Activity 的视图才能被用户看到。 下面是Activity类中的makeVisible()方法。

void makeVisible() {
    if (!mWindowAdded) {
        ViewManager wm = getWindowManager();
        wm.addView(mDecor, getWindow().getAttributes());
        mWindowAdded = true;
    }
    mDecor.setVisibility(View.VISIBLE);
}