大家好,又见面了,我是你们的朋友全栈君。
activity是Android的四大组件之一,负责控制activity的生命周期和处理事件,负责视图的添加与显示,以及通过一些回调方法与window和View进行交互。一个activity包含一个window,window才是真正的窗口
Window是一个抽象类,它真正的实现类是PhoneWindow。Window通过WindowManager加载一个DecorView到Window中,并将DecorView交给ViewRoot。 FrameWork定义了三种窗口类型,三种类型定义在WindowManager,通过LayoutParams.type设置
DecorView是FrameLayout的子类,它可以被认为是Acitivity的视图根节点。是setContentView所设置的View的父容器。
ViewRoot对应ViewRootImp类,它是连接WindowManager和DecorView的纽带,在ActivityThread中,当Activity对象创建完毕后,会将DecorView添加到Window中,同时会创建ViewRootImp对象,并将ViewRootImp对象和DecorView建立关联。View的三大流程measure layout draw都是通过ViewRoot完成。ViewRoot并不属于View树的一部分,从源码上看它既非View的子类,也非View的父类,但是它实现了ViewParent接口,所以可以算作名义上的View的父视图。ViewRoot继承了Handler类,Android所有的触屏事件、按键事件、界面刷新等事件都是通过ViewRoot进行分发的. ViewRootImpl中调用performTraversals方法,然后便开始测量布局绘画了,界面才得以显示出来,这就是View的绘制流程起点。
看下一张图
上图描述了activity、window、decorView和设置View的视图层级关系
先从Activity.java的setContentView()开始
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
可以看到如下步骤:
@Override
public void setContentView(int layoutResID) {
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 {
//生成的布局内容添加到 decoView的contentView中去
mLayoutInflater.inflate(layoutResID, mContentParent);
}
//...
}
上面的方法中主要就是干了2件事:
下面继续看installDecor()方法干了什么
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
//创建decorView
mDecor = generateDecor(-1);
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
} else {
mDecor.setWindow(this);
}
if (mContentParent == null) {
//为decorView设置布局样式,并返回mContentParent
mContentParent = generateLayout(mDecor);
....
}
}
protected DecorView generateDecor(int featureId) {
Context context;
if (mUseDecorContext) {
Context applicationContext = getContext().getApplicationContext();
if (applicationContext == null) {
context = getContext();
} else {
context = new DecorContext(applicationContext, this);
if (mTheme != -1) {
context.setTheme(mTheme);
}
}
} else {
context = getContext();
}
//创建DecorView
return new DecorView(context, featureId, this, getAttributes());
}
generateDecor()的方法很简单,就是获取上下文context,并且实例化DecorView.
protected ViewGroup generateLayout(DecorView decor) {
// 现货区当前主题
TypedArray a = getWindowStyle();
mIsFloating = a.getBoolean(R.styleable.Window_windowIsFloating, false);
int flagsToUpdate = (FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR)
& (~getForcedWindowFlags());
if (mIsFloating) {
setLayout(WRAP_CONTENT, WRAP_CONTENT);
setFlags(0, flagsToUpdate);
} else {
setFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR, flagsToUpdate);
getAttributes().setFitInsetsSides(0);
getAttributes().setFitInsetsTypes(0);
}
//设置窗口特征,
if (a.getBoolean(R.styleable.Window_windowNoTitle, false)) {
requestFeature(FEATURE_NO_TITLE);
} else if (a.getBoolean(R.styleable.Window_windowActionBar, false)) {
// Don't allow an action bar if there is no title.
requestFeature(FEATURE_ACTION_BAR);
}
........
// Inflate the window decor.
//根据主题样式,加载布局
int layoutResource;
int features = getLocalFeatures();
// System.out.println("Features: 0x" + Integer.toHexString(features));
if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = R.layout.screen_title_icons;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
// System.out.println("Title Icons!");
} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {
layoutResource = R.layout.screen_simple_overlay_action_mode;
} else {
// Embedded, so no decoration is needed.
layoutResource = R.layout.screen_simple;
// System.out.println("Simple!");
}
mDecor.startChanging();
//将适配的布局文件生成root,并且调用addView的方法添加到decorview中去
mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
//拿到content通过布局,注意该id的值,获取的就是mContentParent
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
if (contentParent == null) {
throw new RuntimeException("Window couldn't find content container view");
}
if ((features & (1 << FEATURE_INDETERMINATE_PROGRESS)) != 0) {
ProgressBar progress = getCircularProgressBar(false);
if (progress != null) {
progress.setIndeterminate(true);
}
}
// Remaining setup -- of background and title -- that only applies
// to top-level windows.
if (getContainer() == null) {
mDecor.setWindowBackground(mBackgroundDrawable);
final Drawable frame;
if (mFrameResource != 0) {
frame = getContext().getDrawable(mFrameResource);
} else {
frame = null;
}
mDecor.setWindowFrame(frame);
mDecor.setElevation(mElevation);
mDecor.setClipToOutline(mClipToOutline);
if (mTitle != null) {
setTitle(mTitle);
}
if (mTitleColor == 0) {
mTitleColor = mTextColor;
}
setTitleColor(mTitleColor);
}
mDecor.finishChanging();
return contentParent;
}
上面的方法简单的流畅描述下:
注意: 拿到content的过程。上面通过主题加载布局,此次使用R.layout.screen_simple,作为例子来操作下面获取contentParent的过程。
public static final int ID_ANDROID_CONTENT = com.android.internal.R.id.content;
//拿到content
ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
screen_simple不布局内容
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
<FrameLayout
android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foregroundInsidePadding="false"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
改文件内容很简单一个是ViewStub,此用来是设置actionBar的设置,下面一个FrameLayout对应的id是content,所以 mContentParent的就是framelayout。
到此setContentView的流程大致已经结束。以上是decorView已经创建起来。注意此时的DecorVIew还是不可见的。
当DecorView的构造流程完成时此时decorView还没有添加到window中。 ActivityThread的handleResumeActivity方法中,首先会调用Activity的onResume方法,接着调用Activity的makeVisible()方法。 makeVisible()中通过WindowManager.addView()完成了DecorView的添加和显示两个过程
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
//windowManager添加DecorView
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
//设置decorView可见
mDecor.setVisibility(View.VISIBLE);
}
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/153247.html原文链接:https://javaforall.cn
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有