Activity 的 Window 创建过程

2019-12-26 15:29:42 浏览数 (2)

Activity 的 Window 创建过程

Activity Window创建最终在ActivityThread 中的performLaunchActivity方法中,调用Activity的attach方法创建。

调用mWindow = new PhoneWindow(this, window, activityConfigCallback);进行初始化操作; Activity中有一个成员为Window,其实例化对象为PhoneWindow,PhoneWindow为抽象Window类的实现类。

  • Window是一个抽象类,提供了绘制窗口的一组通用API。
  • PhoneWindowWindow的具体继承实现类。而且该类内部包含了一个DecorView对象,该DecorView对象是所有应用窗口(Activity界面)的根View。
  • DecorViewPhoneWindow的内部类,是FrameLayout的子类,是对FrameLayout进行功能的修饰(所以叫DecorXXX),是所有应用窗口的根View

Activity、View、Window关系

一句话概括,Activity像工匠,View像窗花,window像窗户,LayoutInflater像剪刀,Xml像窗花图纸。Activity根据他们不同职能,并且与他们相互配合像我们展示灵活与精致的界面

View如何与Activity进行关联

View并不是直接与Activity关联,而是通过Window这个中间人,Window才是直接关联到Activity上的

Window如何与Activity进行关联

每一个Activity包含一个PhoneWindow,并且PhoneWindow是抽象类Window的子类,setContentView让View与Window关联,Activity与Window关联

总结

Activity包含一个PhoneWindow,而PhoneWindow继承Window,Activity通过setContentView将View设置到PhoneWindow上,而View通过WindowManageraddView,removeView,updateView来对View进行管理,Window的添加过程与Activity启动流程都是一个IPC过程。Activity启动完需要通过AMS完成,而Window添加过程需要通过WindowSession完成。

Activity 视图附加到Window上

通过ActivitysetContentView方法来实现

代码语言:javascript复制
//FEATURE_CONTENT_TRANSITIONS 转场动画
setContentView(R.layout.activity_test_event);

最后调用的是Activity的setContentView方法

代码语言:javascript复制
public void setContentView(@LayoutRes int layoutResID) {
    getWindow().setContentView(layoutResID);
    initWindowDecorActionBar();
}

getWindow返回的是window对象,而window是抽象方法由PhoneWindow实现,所以调用是PhoneWindowsetContentView方法

代码语言:javascript复制
public void setContentView(int layoutResID) {
    // 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.
//判断mContentParent是否为空,这里它是一个viewgroup
    if (mContentParent == null) {
//为空,进行初始化操作
        installDecor();
    } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
//不为空,移除之前所以的子view
        mContentParent.removeAllViews();
    }
//判断是否含有转场动画
    if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
        final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID,
                getContext());
        transitionTo(newScene);
    } else {
//没有使用此方法加载布局,将布局加载到mContentParent中
        mLayoutInflater.inflate(layoutResID, mContentParent);
    }
    mContentParent.requestApplyInsets();
    final Callback cb = getCallback();
    if (cb != null && !isDestroyed()) {
        cb.onContentChanged();
    }
    mContentParentExplicitlySet = true;
}
private void installDecor() {
    mForceDecorInstall = false;
//DecorView为空进行初始化
    if (mDecor == null) {
        mDecor = generateDecor(-1);
        mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
        mDecor.setIsRootNamespace(true);
        if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
            mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
        }
    } else {
//不为空,与PhoneWindow进行关联
        mDecor.setWindow(this);
    }
    if (mContentParent == null) {
//初始化操作,方法内部通过findviewbyid寻找是否存在id为content的Android内部布局FragmentLayout,有返回,
//没有抛异常
        mContentParent = generateLayout(mDecor);
 
        // Set up decor part of UI to ignore fitsSystemWindows if appropriate.
        mDecor.makeOptionalFitsSystemWindows();
 
        final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById(
                R.id.decor_content_parent);
 
        if (decorContentParent != null) {
            mDecorContentParent = decorContentParent;
            mDecorContentParent.setWindowCallback(getCallback());
            if (mDecorContentParent.getTitle() == null) {
                mDecorContentParent.setWindowTitle(mTitle);
            }
 
            final int localFeatures = getLocalFeatures();
            for (int i = 0; i < FEATURE_MAX; i  ) {
                if ((localFeatures & (1 << i)) != 0) {
                    mDecorContentParent.initFeature(i);
                }
            }
 
            mDecorContentParent.setUiOptions(mUiOptions);
 
            if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) != 0 ||
                    (mIconRes != 0 && !mDecorContentParent.hasIcon())) {
                mDecorContentParent.setIcon(mIconRes);
            } else if ((mResourcesSetFlags & FLAG_RESOURCE_SET_ICON) == 0 &&
                    mIconRes == 0 && !mDecorContentParent.hasIcon()) {
                mDecorContentParent.setIcon(
                        getContext().getPackageManager().getDefaultActivityIcon());
                mResourcesSetFlags |= FLAG_RESOURCE_SET_ICON_FALLBACK;
            }
            if ((mResourcesSetFlags & FLAG_RESOURCE_SET_LOGO) != 0 ||
                    (mLogoRes != 0 && !mDecorContentParent.hasLogo())) {
                mDecorContentParent.setLogo(mLogoRes);
            }
            PanelFeatureState st = getPanelState(FEATURE_OPTIONS_PANEL, false);
            if (!isDestroyed() && (st == null || st.menu == null) && !mIsStartingWindow) {
                invalidatePanelMenu(FEATURE_ACTION_BAR);
            }
        } else {
            mTitleView = findViewById(R.id.title);
            if (mTitleView != null) {
                if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) {
                    final View titleContainer = findViewById(R.id.title_container);
                    if (titleContainer != null) {
                        titleContainer.setVisibility(View.GONE);
                    } else {
                        mTitleView.setVisibility(View.GONE);
                    }
                    mContentParent.setForeground(null);
                } else {
                    mTitleView.setText(mTitle);
                }
            }
        }
 
        if (mDecor.getBackground() == null && mBackgroundFallbackResource != 0) {
            mDecor.setBackgroundFallback(mBackgroundFallbackResource);
        }
 
        // Only inflate or create a new TransitionManager if the caller hasn't
        // already set a custom one.
        if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) {
//有转场动画就加载动画资源
            if (mTransitionManager == null) {
                final int transitionRes = getWindowStyle().getResourceId(
                        R.styleable.Window_windowContentTransitionManager,
                        0);
                if (transitionRes != 0) {
                    final TransitionInflater inflater = TransitionInflater.from(getContext());
                    mTransitionManager = inflater.inflateTransitionManager(transitionRes,
                            mContentParent);
                } else {
                    mTransitionManager = new TransitionManager();
                }
            }
 
            mEnterTransition = getTransition(mEnterTransition, null,
                    R.styleable.Window_windowEnterTransition);
            mReturnTransition = getTransition(mReturnTransition, USE_DEFAULT_TRANSITION,
                    R.styleable.Window_windowReturnTransition);
            mExitTransition = getTransition(mExitTransition, null,
                    R.styleable.Window_windowExitTransition);
            mReenterTransition = getTransition(mReenterTransition, USE_DEFAULT_TRANSITION,
                    R.styleable.Window_windowReenterTransition);
            mSharedElementEnterTransition = getTransition(mSharedElementEnterTransition, null,
                    R.styleable.Window_windowSharedElementEnterTransition);
            mSharedElementReturnTransition = getTransition(mSharedElementReturnTransition,
                    USE_DEFAULT_TRANSITION,
                    R.styleable.Window_windowSharedElementReturnTransition);
            mSharedElementExitTransition = getTransition(mSharedElementExitTransition, null,
                    R.styleable.Window_windowSharedElementExitTransition);
            mSharedElementReenterTransition = getTransition(mSharedElementReenterTransition,
                    USE_DEFAULT_TRANSITION,
                    R.styleable.Window_windowSharedElementReenterTransition);
            if (mAllowEnterTransitionOverlap == null) {
                mAllowEnterTransitionOverlap = getWindowStyle().getBoolean(
                        R.styleable.Window_windowAllowEnterTransitionOverlap, true);
            }
            if (mAllowReturnTransitionOverlap == null) {
                mAllowReturnTransitionOverlap = getWindowStyle().getBoolean(
                        R.styleable.Window_windowAllowReturnTransitionOverlap, true);
            }
            if (mBackgroundFadeDurationMillis < 0) {
                mBackgroundFadeDurationMillis = getWindowStyle().getInteger(
                        R.styleable.Window_windowTransitionBackgroundFadeDuration,
                        DEFAULT_BACKGROUND_FADE_DURATION_MS);
            }
            if (mSharedElementsUseOverlay == null) {
                mSharedElementsUseOverlay = getWindowStyle().getBoolean(
                        R.styleable.Window_windowSharedElementsUseOverlay, true);
            }
        }
    }
}
总结:
  1. 创建一个DecorViewmDecor对象,用于做为整个应用窗口的根视图;
  2. view添加到DecorViewmContentParent中;
  3. 依据Featurestyle theme创建不同的窗口修饰布局文件,并且通过findViewById获取Activity布局文件该存放的地方(窗口修饰布局文件中id为content的FrameLayout);
  4. Activity的布局文件添加至id为contentFrameLayout内;
  5. 回调Activity的onContentChanged方法通知Activity视图发生改变,onContentChanged是一个空的实现,可以自己在Activity中实现 final Callback cb = getCallback();     if (cb != null && !isDestroyed()) {         cb.onContentChanged();     }

但是此时DecorView并没有被添加到WindowManager中,没有被识别,无法获取Window的具体功能,需要调用Activity中的makeVisible方法,DecorView才能真正的显示出来。最后ActivityWindow就创建完成了。

代码语言:javascript复制
 void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }

0 人点赞