Android-举一反三:12个View绘制流程高频面试题,带你全面理解View的绘制流程

}

ActivityThread.handleResumeActivity 里会调用 wm.addView 来添加 DecorView,wm 是 WindowManagerImpl

// WindowManagerImpl

public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {

applyDefaultToken(params);

mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);

}

// WindowManagerGlobal

public void addView(View view, ViewGroup.LayoutParams params,

Display display, Window parentWindow) {

// 这里的 view 就是 DecorView

// …

ViewRootImpl root;

View panelParentView = null;

synchronized (mLock) {

// …

root = new ViewRootImpl(view.getContext(), display);

view.setLayoutParams(wparams);

mViews.add(view);

mRoots.add(root);

mParams.add(wparams);

// do this last because it fires off messages to start doing things

try {

root.setView(view, wparams, panelParentView);

} catch (RuntimeException e) {

}

}

}

// ViewRootImpl.setView

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {

requestLayout();

}

最终通过 WindowManagerImpl.addView -> WindowManagerGlobal.addView -> ViewRootImpl.setView -> ViewRootImpl.requestLayout 就触发了第一次 View 的绘制。

2. ViewRootImpl 创建的时机?

从上面流程里可以看到,ViewRootImpl 也是在 ActivityThread.handleResumeActivity 里创建的。

3. ViewRootImpl 和 DecorView 的关系是什么?

// ViewRootImpl.setView

public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {

requestLayout();

// …

// 这里的 view 是 DecorView

view.assignParent(this);

}

接着上面的代码看,在 ViewRootImpl.setView 里,通过 DecorView.assignParent 把 ViewRootImpl 设置为 DecorView 的 parent。

所以 ViewRootImpl 和 DecorView 的关系就是 ViewRootImpl 是 DecorView 的 parent。

因为 DecorView 是我们布局的顶层,现在我们就知道层层调用 requestLayout 等方法是怎么调用到 ViewRootImpl 里的了。

4. DecorView 的布局是什么样的?

对于 Activity 的层级,大家应该都看过一张图的描述,Activity -> PhoneWindow -> DecorView -> [title_bar, content],其中 DecorView 里包括了 title_bar 和 content 两个 View,不过这个是默认的布局,实际上根据不同的主题样式,DecorView 对应有不同的布局。

图中所包含的 title_bar 和 content 对应的是 R.layout.screen_simple 布局。

那么这么多布局,是在什么时候设置的呢?

是在 PhoneWindow.installDecor -> generateLayout 中设置的。

// PhoneWindow

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) {

mContentParent = generateLayout(mDecor); // 生成 DecorView 子View

}

}

protected ViewGroup generateLayout(DecorView decor) {

// 根据不同的 window feature 给 DecorView 设置不同的布局

int layoutResource;

int features = getLocalFeatures();

if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) {

layoutResource = R.layout.screen_swipe_dismiss;

setCloseOnSwipeEnabled(true);

} else 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;

}

removeFeature(FEATURE_ACTION_BAR);

} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0

&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {

layoutResource = R.layout.screen_progress;

} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {

if (mIsFloating) {

TypedValue res = new TypedValue();

getContext().getTheme().resolveAttribute(

R.attr.dialogCustomTitleDecorLayout, res, true);

layoutResource = res.resourceId;

} else {

layoutResource = R.layout.screen_custom_title;

}

removeFeature(FEATURE_ACTION_BAR);

} else if ((features & (1 << FEATURE_NO_TITLE)) == 0) {

if (mIsFloating) {

TypedValue res = new TypedValue();

getContext().getTheme().resolveAttribute(

R.attr.dialogTitleDecorLayout, res, true);

layoutResource = res.resourceId;

} else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {

layoutResource = a.getResourceId(

R.styleable.Window_windowActionBarFullscreenDecorLayout,

R.layout.screen_action_bar);

} else {

layoutResource = R.layout.screen_title;

}

} else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) {

layoutResource = R.layout.screen_simple_overlay_action_mode;

} else {

// 默认布局

layoutResource = R.layout.screen_simple;

}

mDecor.startChanging();

mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);

}

// DecorView

void onResourcesLoaded(LayoutInflater inflater, int layoutResource) {

// 根据 上一步选择的 layout 生成 View

final View root = inflater.inflate(

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值