LayoutInflater 布局填充阶段,按既有的布局填充流程,将 SurfaceView 构造并加入到视图树的某个结点;接下来,根布局会通过深度遍历依次执行 onAttachedToWindow() 处理视图挂载窗口的事件:
// /frameworks/base/core/java/android/view/SurfaceView.java
@Override
protected void onAttachedToWindow() {
// ...
mParent.requestTransparentRegion(SurfaceView.this); // 1.
ViewTreeObserver observer = getViewTreeObserver();
observer.addOnPreDrawListener(mDrawListener); // 2.
}
@UnsupportedAppUsage
private final ViewTreeObserver.OnPreDrawListener mDrawListener = new ViewTreeObserver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
updateSurface(); // 3.
return true;
}
};
protected void updateSurface() {
// ...
mSurfaceSession = new SurfaceSession();
mSurfaceControl = new SurfaceControl.Builder(mSurfaceSession); // 4
//...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
步骤 1 中,SurfaceView 会向父视图依次向上请求创造一份透明区域,根视图统计到最终的信息后,通过 Binder 通知 WindowManagerService 将对应区域设置为透明。
步骤 2、3、4 是在同一个方法的调用栈中,由此可见,SurfaceView 向系统请求透明区域后,会立即创建一个与绘图表面的连接 SurfaceSession ,并创建一个对应的控制器 SurfaceControl,便于对这个独立的绘图表面进行直接通信。
由此可见,Android 自有的视图树体系中,SurfaceView 作为一个普通的 View 被挂载上去之后,通过 Binder 通信,WindowManagerService 将其所在区域设置为透明(挖洞);并建立了与独立绘图表面的连接,后续便可与其直接通信。
- 子图层类型
在阐述绘制流程之前,读者需简单了解 子图层类型 的概念。
上文说到,SurfaceView 的绝大多数使用场景中,其 z 轴的位置通常是在页面的 最下方 。但在实际开发中,随着业务场景复杂度的上升,仍然有部分场景是无法被满足的,比如:在页面的最上方播放一条全屏的视频广告。
因此,SurfaceView 的设计中引入了一个 子图层类型 的概念,用于定义这个独立的 Surface 相比较当前页面窗口 (即Activity) 的位置:
// /frameworks/base/core/java/android/view/SurfaceView.java
public class SurfaceView extends View {
// SurfaceView 的子图层类型
int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
// SurfaceView 是否展示在当前窗口的最上方
// 该方法在挖洞和绘制流程中都有使用,最终影响到用户的视觉效果
private boolean isAboveParent() {
return mSubLayer >= 0;
}
}
// /frameworks/base/core/java/android/view/WindowManagerPolicyConstants.java
public interface WindowManagerPolicyConstants {
// ...
int APPLICATION_MEDIA_SUBLAYER = -2;
int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
int APPLICATION_PANEL_SUBLAYER = 1;
int APPLICATION_SUB_PANEL_SUBLAYER = 2;
int APPLICATION_ABOVE_SUB_PANEL_SUBLAYER = 3;
// ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
如代码所示,mSubLayer 默认值为 -2,这表示 SurfaceView 默认总是在 Activity 的下方,想要让 SurfaceView 展示在 Activity 上方,可以调用 setZOrderOnTop(true) 以修改 mSubLayer 的值:
————————————————