☰
从0开始写android 之onResume
2026/10/28 1:14:48 网站建设 项目流程


前言

接上文, android源码在onCreate后, 即创建DecorView 为根节点的树型结构。这个树形结构非常重要,后续图形的测量,布局,绘制和点击事件的传递都是以这个树形结构为前提。接着就开始走onResume流程,在onResume 创建了ViewRootImpl, 在ViewRootImpl的addView中,分三步走 1.创建窗口,2.注册事件接收,3.将图像画到窗口上。其中将图像画到窗口上,调用了performTraversal 函数, 这个函数中实现了 三个主要流程, performMeasure, performLayout, performDraw 。本文将着重描述 performMeasure 即测量 DecorView 的整个算法和数据结构


handleResumeActivity ViewRootImpl.setView() → IWindowManager.addWindow(..., outInputChannel) → WMS addWindow → 校验权限、token、display → new WindowState → 条件满足:win.openInputChannel(outInputChannel) → IMS createInputChannel 创建socketpair → copyTo(outInputChannel) 把client端fd塞回binder输出参数 → Binder 返回,ViewRootImpl拿到 outInputChannel → new InputEventReceiver(channel, mLooper) → 监听socket fd,接收IMS下发触摸/按键事件 主线程消息循环继续跑,等到轮到 MSG_DO_LAYOUT: → performTraversals() → measure → layout → draw

一,创建窗口

创建窗口是调用WindowManagerService的addWindow, 在addWindow里创建WindowState.

  • Activity 主窗口(DecorView)
  • Dialog、PopupWindow、Toast、悬浮窗 TYPE_APPLICATION_OVERLAY
  • 状态栏、导航栏、锁屏、输入法窗口、系统弹窗(系统窗口) 它们统一路径:WindowManager.addView → ViewRootImpl.setView → IWindowSession.addToDisplayAsUser → WMS.addWindowWMS 内部创建WindowState,登记 token、分配 InputChannel、管理焦点、Z 序、动画、Insets。

二, 注册事件接收

三, 将图像画到窗口上

在复现onMeasure 的流程前, 有必要理清 view 和 viewgroup 的关系。

2.1、最简单的view 和viewgroup

public class View { protected Context mContext; public View(Context context) { mContext = context; } public View(Context context, AttributeSet attrs) { this(context, attrs, 0); } public View(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public View(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { this(context); } }

一个最简单的view类 ,此时仅有 mContext 成员变量和 四个构造函数。其他的成员变量在需要的时候,我们再添加进来。

ViewGroup 的简单实现稍微复杂一点.

public abstract class ViewGroup extends View implements ViewParent { private View[] mChildren; private int mChildrenCount; private static final int ARRAY_INITIAL_CAPACITY = 12; private static final int ARRAY_CAPACITY_INCREMENT = 12; private String TAG="ViewGroup."; public ViewGroup(Context context) { this(context, null); } public ViewGroup(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr) { this(context, attrs, defStyleAttr, 0); } public ViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); initViewGroup(); // initFromAttributes(context, attrs, defStyleAttr, defStyleRes); } private void initViewGroup() { mChildren = new View[ARRAY_INITIAL_CAPACITY]; mChildrenCount = 0; } public void addView(View child, LayoutParams params) { Log.d(TAG, "addView "+child); addView(child, -1, params); } public void addView(View child, int index, LayoutParams params) { // requestLayout(); addViewInner(child, index, params, false); } private void addViewInner(View child, int index, LayoutParams params, boolean preventRequestLayout) { if (preventRequestLayout) { child.mLayoutParams = params; } else { child.setLayoutParams(params); } if (index < 0) { index = mChildrenCount; } addInArray(child, index); child.mParent = this; } private void addInArray(View child, int index) { View[] children = mChildren; final int count = mChildrenCount; final int size = children.length; if (index == count) { if (size == count) { mChildren = new View[size + ARRAY_CAPACITY_INCREMENT]; System.arraycopy(children, 0, mChildren, 0, size); children = mChildren; } children[mChildrenCount++] = child; } else if (index < count) { if (size == count) { mChildren = new View[size + ARRAY_CAPACITY_INCREMENT]; System.arraycopy(children, 0, mChildren, 0, index); System.arraycopy(children, index, mChildren, index + 1, count - index); children = mChildren; } else { System.arraycopy(children, index, children, index + 1, count - index); } children[index] = child; mChildrenCount++; // if (mLastTouchDownIndex >= index) { // mLastTouchDownIndex++; // } } else { throw new IndexOutOfBoundsException("index=" + index + " count=" + count); } } public int getChildCount() { return mChildrenCount; } public View getChildAt(int index) { if (index < 0 || index >= mChildrenCount) { return null; } return mChildren[index]; } }

ViewGroup 设计为抽象类,继承自view。 有View类型的数组成员 child, 因为child是数组类型,所以对应有一系列的 add, get 等操作。

2.2、performMeasure 流程

在上一篇我们知道 DecorView 是一个树形数据结构的根节点。

1. 已知条件

ViewRootImpl.setView 时 ,实际上我们拿到了窗口的大小。 即一个矩形 例如(0, 40, 1920,1121)。
Rect frame = mWinFrame;
desiredWindowWidth = frame.width(); desiredWindowHeight = frame.height();

拿到窗口的大小, 我们就从这个大小开始开始测量。

2. onMeasure

因为总的窗口大小已知

ViewRootImpl->performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); View-> measure(childWidthMeasureSpec, childHeightMeasureSpec);

DecorView-> onMeasure

FrameLayout ->OnMeasure onMeasure 的实现由继承自view 的类实现,view 本身也有个实现
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec), getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec)); } protected final void setMeasuredDimension(int measuredWidth, int measuredHeight) { boolean optical = isLayoutModeOptical(this); if (optical != isLayoutModeOptical(mParent)) { Insets insets = getOpticalInsets(); int opticalWidth = insets.left + insets.right; int opticalHeight = insets.top + insets.bottom; measuredWidth += optical ? opticalWidth : -opticalWidth; measuredHeight += optical ? opticalHeight : -opticalHeight; } setMeasuredDimensionRaw(measuredWidth, measuredHeight); } private void setMeasuredDimensionRaw(int measuredWidth, int measuredHeight) { mMeasuredWidth = measuredWidth; mMeasuredHeight = measuredHeight; mPrivateFlags |= PFLAG_MEASURED_DIMENSION_SET; }

默认实现,实际上就是给 View 的两个成员变量

mMeasuredWidth
mMeasuredHeight 赋值。

如果 view 的子类不使用默认的实现, 则定义自己的onMeasure 规则,例如FrameLayout 不过最终会调用

setMeasuredDimension 给自己的 mMeasureWidth 和 mMeasureHeight 赋值。

总结

提示:这里对文章进行总结:

onResume 的代码上下文远比给APP这边看到的更为复杂。它代表窗口已经就绪、能接收输入、能渲染 。是对用户可见、可以交互的起点。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询