Activity 的 Window 创建过程
Activity Window创建最终在ActivityThread 中的performLaunchActivity方法中,调用Activity的attach方法创建。
调用mWindow = new PhoneWindow(this, window, activityConfigCallback);
进行初始化操作;
Activity
中有一个成员为Window
,其实例化对象为PhoneWindow,PhoneWindow
为抽象Window类的实现类。
Window
是一个抽象类,提供了绘制窗口的一组通用API。PhoneWindow
是Window
的具体继承实现类。而且该类内部包含了一个DecorView
对象,该DecorView
对象是所有应用窗口(Activity界面)的根View。DecorView
是PhoneWindow
的内部类,是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通过WindowManager
的addView,removeView,updateView
来对View进行管理,Window的添加过程与Activity启动流程都是一个IPC过程。Activity启动完需要通过AMS
完成,而Window添加过程需要通过WindowSession
完成。
Activity 视图附加到Window上
通过Activity
的setContentView
方法来实现
//FEATURE_CONTENT_TRANSITIONS 转场动画
setContentView(R.layout.activity_test_event);
最后调用的是Activity的setContentView
方法
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
getWindow
返回的是window
对象,而window
是抽象方法由PhoneWindow
实现,所以调用是PhoneWindow
的setContentView
方法
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);
}
}
}
}
总结:
- 创建一个
DecorView
的mDecor
对象,用于做为整个应用窗口的根视图; - 将
view
添加到DecorView
的mContentParent
中; - 依据
Feature
等style theme
创建不同的窗口修饰布局文件,并且通过findViewById获取Activity布局文件该存放的地方(窗口修饰布局文件中id为content
的FrameLayout); - 将
Activity
的布局文件添加至id为content
的FrameLayout
内; - 回调Activity的
onContentChanged
方法通知Activity视图发生改变,onContentChanged
是一个空的实现,可以自己在Activity中实现 final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); }
但是此时DecorView
并没有被添加到WindowManager
中,没有被识别,无法获取Window的具体功能,需要调用Activity
中的makeVisible
方法,DecorView
才能真正的显示出来。最后Activity
的Window
就创建完成了。
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}