View的加载
Activity关联window
ActivityThread#performLaunchActivity
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
...
Activity activity = null;
try {
java.lang.ClassLoader cl = appContext.getClassLoader();
// 通过反射创建出activity对象
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) {
...
}
try {
...
if (activity != null) {
...
// activity内部初始化window实例PhoneWindow
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, r.configCallback);
...
// 调用Activity的onCreate方法
if (r.isPersistable()) {
mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
} else {
mInstrumentation.callActivityOnCreate(activity, r.state);
}
...
}
r.setState(ON_CREATE);
mActivities.put(r.token, r);
} catch (SuperNotCalledException e) {
throw e;
} catch (Exception e) {
...
}
return activity;
}
创建和初始化DecorView
Activity#setContentView
public void setContentView(View view) {
getWindow().setContentView(view);
initWindowDecorActionBar();
}
PhoneWindow#setContentView
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 {
// 将布局加载进R.id.content的frameLayout中
mLayoutInflater.inflate(layoutResID, mContentParent);
}
// 通知Activity视图发生改变
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
...
}
PhoneWindow#installDecor
private void installDecor() {
mForceDecorInstall = false;
if (mDecor == null) {
// 创建DecorView对象,这个就是根View,是一个FrameLayout
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) {
// 通过窗口类型获取到布局id,创建出对应的View,加载进DecorView中(mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);)
// 因为这个条件也是为什么代码中写隐藏标题栏要写在setContentView上面的原因
// 常规加载布局是screen_title.xml,上面ViewStub用来显示ActionBar的,下面一个FrameLayout是title显示标题的,另一个FrameLayout为主要填充区域
// mContentParent就是这个id是R.id.content
mContentParent = generateLayout(mDecor);
...
}
}
screen_title.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:fitsSystemWindows="true">
<!-- Popout bar for action modes -->
<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:layout_width="match_parent"
android:layout_height="?android:attr/windowTitleSize"
style="?android:attr/windowTitleBackgroundStyle">
<TextView android:id="@android:id/title"
style="?android:attr/windowTitleStyle"
android:background="@null"
android:fadingEdge="horizontal"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
由此可知,调用setContentView会创建和初始化DecorView。但是这个时候DecorView还没有被WindowManager正式添加到Window中。
DecorView添加和显示
public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
String reason) {
...
// 执行Activity的onResume方法
final ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
...
if (r.window == null && !a.mFinished && willBeVisible) {
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
// decorView隐藏
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
...
if (a.mVisibleFromClient) {
if (!a.mWindowAdded) {
a.mWindowAdded = true;
// 后面会着重讲,里面初始化ViewRootImpl,通过WindowSession最终来完成Window的添加过程。
// 这个步骤完成DecorView添加进window中
wm.addView(decor, l);
} else {
a.onWindowAttributesChanged(l);
}
}
} else if (!willBeVisible) {
if (localLOGV) Slog.v(TAG, "Launch " + r + " mStartedActivity set");
r.hideForNow = true;
}
cleanUpPendingRemoveWindows(r, false /* force */);
if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
...
// DecorView显示,到这里Activity的视图才能被用户看到
if (r.activity.mVisibleFromClient) {
r.activity.makeVisible();
}
}
...
}
Activity#makeVisible
void makeVisible() {
if (!mWindowAdded) {
ViewManager wm = getWindowManager();
wm.addView(mDecor, getWindow().getAttributes());
mWindowAdded = true;
}
mDecor.setVisibility(View.VISIBLE);
}
Activity,Window,View关系
在onCreate方法之前,Activity调用attach方法创建Window。
Window通过setContentView创建DecorView,并将布局加载进DecorView的R.id.content中,有标题栏处理标题栏。
在onResume方法之后,调用windowManager的addView方法,将DecorView添加进window中。调用makeVisible方法将DecorView显示出来。
ViewRootImpl
布局检查机制:ViewRootImpl
View的绘制是由ViewRootImpl来负责的。每个应用程序窗口的DecorView都有一个与之关联的ViewRootImpl对象,这种关联关系是由WindowManager来维护的。
ViewRootImpl初始化
ActivityThread#handleResumeActivity
调用wm.addView(decor, l);
参数是DecorView,窗口布局参数。
这个addView方法是在onResume方法之后调用。
WindowManager是对外提供的接口,实例类是WindowManagerImpl。
WindowManagerImpl#addView
public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
applyDefaultToken(params);
mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
mContext.getUserId());
}
WindowManagerGlobal#addView
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow, int userId) {
...
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
...
// 创建ViewRootImpl实例
root = new ViewRootImpl(view.getContext(), display);
view.setLayoutParams(wparams);
mViews.add(view);
mRoots.add(root);
mParams.add(wparams);
try {
// view是DecorView,这行代码将开始绘制view
root.setView(view, wparams, panelParentView, userId);
} catch (RuntimeException e) {
// BadTokenException or InvalidDisplayException, clean up.
if (index >= 0) {
removeViewLocked(index, true);
}
throw e;
}
}
}
View绘制
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
int userId) {
synchronized (this) {
if (mView == null) {
...
//进行View布局绘制
requestLayout();
...
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
adjustLayoutParamsForCompatibility(mWindowAttributes);
// 通过WindowSession最终来完成Window的添加过程。
// mWindowSession的类型是IWindowSession,它是一个Binder对象,真正的实现类是Session,也就是Window的添加过程是一次IPC调用。
// 在Session内部会通过WMS来实现Window的添加
res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
mAttachInfo.mDisplayCutout, inputChannel,
mTempInsets, mTempControls);
setFrame(mTmpFrame);
} catch (RemoteException e) {
mAdded = false;
mView = null;
mAttachInfo.mRootView = null;
inputChannel = null;
mFallbackEventHandler.setView(null);
unscheduleTraversals();
setAccessibilityFocus(null, null);
throw new RuntimeException("Adding window failed", e);
} finally {
if (restore) {
attrs.restore();
}
}
...
// 注意这里,ViewRootImpl实现ViewParent接口,这里将ViewRootImpl抽象为DecorView的父布局,注意只是抽象,ViewRootImpl并不是View
view.assignParent(this);
...
}
}
}
ViewRootImpl#requestLayout
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
// 线程检测
checkThread();
mLayoutRequested = true;
// 绘制方法doTraversal是在下次loop循环才去调用而不是立即调用
// doTraversal方法中调用performTraversals使ViewTree开始View绘制
// 分别调用performMeasure,performLayout,performDraw,在其内部又会分别调用View的measure,layout,draw方法
scheduleTraversals();
}
}