我们都知道Activity的层有一个Window也有一个WindowManage其中对应如下
Activity所拥有的Window与 WindowManage
1.PhoneWindow
2.PhoneWindowManage
在刚开始我们设置的时候是这样设置的
setContentView(R.layout.activity_main);
我们跟进一下
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID); //主要看这个,我们先看看这个getWindow是什么
initWindowDecorActionBar();//这个是DecorView初始化ActionBar的,
//DecorView为整个Activity也就是整个
//PhoneWindow底层的View
}
我们先看看这个getWindow是什么
public Window getWindow() {
return mWindow; //直接return了一个mWindow
}
//看一下这个mWindow是什么
mWindow = new PhoneWindow(this, window, activityConfigCallback); //底层就是PhoneWindow
//再来看一下WindowManage
mWindowManager = mWindow.getWindowManager();
//也就是说用的是PhoneWindow的WindowManager
我们继续跟进到PhoneWindow类里边
回到我们的setContentView
/**
* XINHAO_HAN 设置Activity的View
* @param layoutResID
*/
@Override
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 {
mLayoutInflater.inflate(layoutResID, mContentParent);
}
mContentParent.requestApplyInsets();
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
//如果视图跟新就通知外部类
cb.onContentChanged();
}
mContentParentExplicitlySet = true;
}
我们继续看一下 installDecor();
private void installDecor() {
mForceDecorInstall = false;
//如果DecorView为空就开始设置DecorView
if (mDecor == null) {
//Decor就是在这里创建的,我们看一下这个方法
mDecor = generateDecor(-1);
//获取焦点
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
......
}
我们看一下这个方法 generateDecor(-1);
protected DecorView generateDecor(int featureId) {
// System process doesn't have application context and in that case we need to directly use
// the context we have. Otherwise we want the application context, so we don't cling to the
// activity.
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, getContext().getResources());
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
return new DecorView(context, featureId, this, getAttributes());
}
这块是直接new了一个DecorView,就相当于要添加到PhoneWindow里边的View
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);
}
//这块是设置了一些用户设置的主题什么的
然后感觉没了? 没了??不可能啊,它应该是有一个东西添加到WindowManager里边的,否则什么都不会显示
然后我在ActivityThread里边找到了它添加的一些方法
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) {
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();
}
}
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
//重点在这里------------------------------------------------------------------------------------
wm.addView(decor, l);
} else {
// The activity will get a callback for this {@link LayoutParams} change
// earlier. However, at that time the decor will not be set (this is set
// in this method), so no action will be taken. This call ensures the
// callback occurs with the decor set.
a.onWindowAttributesChanged(l);
}
}
我们可以看出在Activity相当于一个PhoneWindow一个维护类.
当所有东西都初始化好了(getDecorView和PhoneWindow)以后再ActivityThread中直接调用
知识点(总结)
1.Activity中的setContentView实际上是给Activity对应的Window设置
2.Activity对应的Window是PhoneWindow
3.Activity的根目录为DecorView,在 Android当中有一个实体id android.R.id.content
4.Activity添加布局是在ActivityThread中添加的,并且在PhoneWindow初始化好之后(DecorView)
5.DecorView的布局是集成于FramLayout,并且有统一的格式,包括我们看到的,状态栏,布局,TitleBar,
6.可以说是以外得把,你可以试试用Activity的WindowManager添加一个View,然后用getApplicationContext的WindowManager添加一个View然后对比效果
效果是如下的,Activity-WindowManager添加的View只能依附在于Activity上不能依附在所有APP上边,Activity销毁后可能会提示窗口泄露,没有移除掉,但是不会奔溃,只是提示,Activity-WindowManager所添加的View是根据Activity的生命周期而变化的(绑定在一起的),而getApplicationContext所添加的WindowManager的View是飘在整个系统上边的