SV继承自View,但是并不是利用View的Draw来进行绘制。而是直接跟SurfaceFlinger进行通信。那么看下具体SV是怎么实现这个功能的,它的用法如何?
还是先从构造方法开始看起。
public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
//Enable callbacks for position changes.
mRenderNode.requestPositionUpdates(this);
//此方法规定不会走正常的draw方法。
setWillNotDraw(true);
}
假设我们直接贴一个SurfaceView 到布局中,给SV一定宽高,SV会形成一个"黑洞"区域。如图。
现在来分析下这是如何形成的。
由于SV也是一个View,只是绘制的时候会走自己的绘制机制。对于常规的onMesure和onLayout还是一样会跑的。这个也是SV得以能够进行绘制的前提条件,因为你必须首先有大小,然后有位置,其次才是在具体位置利用画笔(paint)进行绘制的。那么先来看看onMeasure。
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//mRequestedWidth 由setFixedSize设置,默认情况是-1。那么默认是走getDefaultSize.也就是基本的测量方法。
int width = mRequestedWidth >= 0
? resolveSizeAndState(mRequestedWidth, widthMeasureSpec, 0)
: getDefaultSize(0, widthMeasureSpec);
int height = mRequestedHeight >= 0
? resolveSizeAndState(mRequestedHeight, heightMeasureSpec, 0)
: getDefaultSize(0, heightMeasureSpec);
setMeasuredDimension(width, height);
}
所以onMeasure可以说平平无奇。
接下来看下布局。发现SV并没有重写这个onLayout方法。但是有重写setFrame方法,这个方法是View中,layout过程调用的。所以布局的时候必然会走到这个setFrame方法。
/** @hide */
@Override
protected boolean setFrame(int left, int top, int right, int bottom) {
boolean result = super.setFrame(left, top, right, bottom);
updateSurface();
return result;
}
这里面的关键方法就是updateSurface方法.
/** @hide */
protected void updateSurface() {
//判断是否有长宽。经历了measure之后mHaveFrame为true.
if (!mHaveFrame) {
return;
}
//获取View 根。
ViewRootImpl viewRoot = getViewRootImpl();
//主要看最后一个就是说View的mSurface是否准备完毕。也就是说,必须ViewTree的surface准备完毕才会走到后面的方法。正常流程经历了onResume,surface准备完毕,才会发起requestlayout,才会有布局的。
if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
return;
}
// mTranslator 属于一个转换器。
mTranslator = viewRoot.mTranslator;
if (mTranslator != null) {
mSurface.setCompatibilityTranslator(mTranslator);
}
int myWidth = mRequestedWidth;
if (myWidth <= 0) myWidth = getWidth();
int myHeight = mRequestedHeight;
if (myHeight <= 0) myHeight = getHeight();
final boolean formatChanged = mFormat != mRequestedFormat;
final boolean visibleChanged = mVisible != mRequestedVisible;
//判断Surface是否正在创建状态,但是没有创建完毕。从这里也可以看到SF的surface和ViewRoot的surfcace并不是同一个。
final boolean creating = (mSurfaceControl == null || formatChanged || visibleChanged)
&& mRequestedVisible;
final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
boolean redrawNeeded = false;
if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
//获取sf控件在其整个屏幕上的坐标位置,并且存储在mLocation中。
getLocationInWindow(mLocation);
try {
final boolean visible = mVisible = mRequestedVisible;
mWindowSpaceLeft = mLocation[0];
mWindowSpaceTop = mLocation[1];
mSurfaceWidth = myWidth;
mSurfaceHeight = myHeight;
mFormat = mRequestedFormat;
mLastWindowVisibility = mWindowVisibility;
mScreenRect.left = mWindowSpaceLeft;
mScreenRect.top = mWindowSpaceTop;
mScreenRect.right = mWindowSpaceLeft + getWidth();
mScreenRect.bottom = mWindowSpaceTop + getHeight();
if (mTranslator != null) {
mTranslator.translateRectInAppWindowToScreen(mScreenRect);
}
final Rect surfaceInsets = getParentSurfaceInsets();
mScreenRect.offset(surfaceInsets.left, surfaceInsets.top);
if (creating) {
//通过ViewRoot的surface创建mSurfaceSession,这个变量用于根SurfaceFlinger进行交互。
mSurfaceSession = new SurfaceSession(viewRoot.mSurface);
mDeferredDestroySurfaceControl = mSurfaceControl;
updateOpaqueFlag();
//mSurfaceControl 从字面来看就是Surface的管理类,里面主要都是native方法。
mSurfaceControl = new SurfaceControlWithBackground(mSurfaceSession,
"SurfaceView - " + viewRoot.getTitle().toString(),
mSurfaceWidth, mSurfaceHeight, mFormat,
mSurfaceFlags);
} else if (mSurfaceControl == null) {
return;
}
boolean realSizeChanged = false;
mSurfaceLock.lock();
try {
mDrawingStopped = !visible;
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "Cur surface: " + mSurface);
//SC开启一次事务。
SurfaceControl.openTransaction();
try {
//mSublayout属于一个type。SV的类型为APPLICATION_MEDIA_SUBLAYER
mSurfaceControl.setLayer(mSubLayer);
if (mViewVisibility) {
mSurfaceControl.show();
} else {
mSurfaceControl.hide();
}
//设置Surface的位置。矩阵。
if (sizeChanged || creating || !mRtHandlingPositionUpdates) {
mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
0.0f, 0.0f,
mScreenRect.height() / (float) mSurfaceHeight);
}
if (sizeChanged) {
mSurfaceControl.setSize(mSurfaceWidth, mSurfaceHeight);
}
} finally {
SurfaceControl.closeTransaction();
}
if (sizeChanged || creating) {
redrawNeeded = true;
}
mSurfaceFrame.left = 0;
mSurfaceFrame.top = 0;
if (mTranslator == null) {
mSurfaceFrame.right = mSurfaceWidth;
mSurfaceFrame.bottom = mSurfaceHeight;
} else {
float appInvertedScale = mTranslator.applicationInvertedScale;
mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
}
final int surfaceWidth = mSurfaceFrame.right;
final int surfaceHeight = mSurfaceFrame.bottom;
realSizeChanged = mLastSurfaceWidth != surfaceWidth
|| mLastSurfaceHeight != surfaceHeight;
mLastSurfaceWidth = surfaceWidth;
mLastSurfaceHeight = surfaceHeight;
} finally {
mSurfaceLock.unlock();
}
try {
redrawNeeded |= visible && !mDrawFinished;
SurfaceHolder.Callback callbacks[] = null;
final boolean surfaceChanged = creating;
if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
mSurfaceCreated = false;
if (mSurface.isValid()) {
//需要重建mSurface
callbacks = getSurfaceCallbacks();
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceDestroyed(mSurfaceHolder);
}
if (mSurface.isValid()) {
mSurface.forceScopedDisconnect();
}
}
}
//如果正在创建,直接copyFrom
if (creating) {
mSurface.copyFrom(mSurfaceControl);
}
//如果size改变。并且考虑兼容性,需要直接createFrom
if (sizeChanged && getContext().getApplicationInfo().targetSdkVersion
< Build.VERSION_CODES.O) {
mSurface.createFrom(mSurfaceControl);
}
//此时mSurface已经可以用了。可以愉快的进行lockCanvas
if (visible && mSurface.isValid()) {
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true;
mIsCreating = true;
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
//此处就是回调callback,我们自定义SV可以在这个方法里面拿到surface。
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceCreated(mSurfaceHolder);
}
}
//size 改变的情形。
if (creating || formatChanged || sizeChanged
|| visibleChanged || realSizeChanged) {
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "surfaceChanged -- format=" + mFormat
+ " w=" + myWidth + " h=" + myHeight);
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceChanged(mSurfaceHolder, mFormat, myWidth, myHeight);
}
}
//需要重新绘制的情形。
if (redrawNeeded) {
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "surfaceRedrawNeeded");
if (callbacks == null) {
callbacks = getSurfaceCallbacks();
}
mPendingReportDraws++;
viewRoot.drawPending();
SurfaceCallbackHelper sch =
new SurfaceCallbackHelper(this::onDrawFinished);
sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
}
}
} finally {
mIsCreating = false;
//如果到这里还是没有创建成功,那么需要释放mSurface。
if (mSurfaceControl != null && !mSurfaceCreated) {
mSurface.release();
// If we are not in the stopped state, then the destruction of the Surface
// represents a visual change we need to display, and we should go ahead
// and destroy the SurfaceControl. However if we are in the stopped state,
// we can just leave the Surface around so it can be a part of animations,
// and we let the life-time be tied to the parent surface.
if (!mWindowStopped) {
mSurfaceControl.destroy();
mSurfaceControl = null;
}
}
}
} catch (Exception ex) {
Log.e(TAG, "Exception configuring surface", ex);
}
} else {
//此处else,是针对surface非初始化创建的情形,也就是surface可利用的情形。
getLocationInSurface(mLocation);
final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
|| mWindowSpaceTop != mLocation[1];
final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
|| getHeight() != mScreenRect.height();
if (positionChanged || layoutSizeChanged) { // Only the position has changed
mWindowSpaceLeft = mLocation[0];
mWindowSpaceTop = mLocation[1];
// For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
// in view local space.
mLocation[0] = getWidth();
mLocation[1] = getHeight();
mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
mWindowSpaceLeft + mLocation[0], mWindowSpaceTop + mLocation[1]);
if (mTranslator != null) {
mTranslator.translateRectInAppWindowToScreen(mScreenRect);
}
if (mSurfaceControl == null) {
return;
}
if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
try {
setParentSpaceRectangle(mScreenRect, -1);
} catch (Exception ex) {
Log.e(TAG, "Exception configuring surface", ex);
}
}
}
}
}
通过这个方法,surface已经创建完毕,并且位置和大小也确定了,所以会留下一个黑洞。如果想要绘制内容,需要实现 SurfaceHolder.Callback。下面是个demo,结合我上面的分析,能够对SV的绘制机制有更深入了解。
public class SurfaceViewDemo extends SurfaceView implements SurfaceHolder.Callback{
private SurfaceHolder mSurfaceHolder;
private Canvas mCanvas;
private Paint paint;
public SurfaceViewDemo(Context context) {
this(context,null,0);
}
public SurfaceViewDemo(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public SurfaceViewDemo(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
mSurfaceHolder = getHolder();
mSurfaceHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.RED);
paint.setStrokeWidth(5);
paint.setStyle(Paint.Style.STROKE);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
System.out.println("=========surfaceCreated========");
new Thread(new Runnable() {
@Override
public void run() {
draw();
}
}).start();
}
private void draw() {
try {
System.out.println("============draw========");
mCanvas = mSurfaceHolder.lockCanvas();
mCanvas.drawCircle(500,500,300,paint);
mCanvas.drawCircle(100,100,20,paint);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (mCanvas != null)
mSurfaceHolder.unlockCanvasAndPost(mCanvas);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
System.out.println("=========surfaceChanged========");
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("=========surfaceDestroyed========");
}
}
通过对SurfaceView机制的分析,可以得知,实际上SV是自己独占一个Surface。好处就是摆脱了View自带的绘制机制,比如说主线程绘制,必须是VSYNC 才能绘制等缺点。