SurfaceView原理简述

更新时间:2023-06-13 21:24:37 阅读: 评论:0

SurfaceView原理简述
以前有个疑问,SurfaceView为什么可以开⼀个新的线程进⾏绘制,⽽其他的不⾏。我们知道View的布局绘制是在主线程执⾏的,通过ViewRootImpl的performTraversals⽅法开始驱动顶层DecorView和它的⼦View执⾏measure,layout, draw。同样是View类,那为什么SurfaceView的绘制操作却可以单独开新的线程去执⾏呢?
在这⾥先提前总结⼀下原理。View的绘制是由ViewRootImpl的Surface对象将绘制后的ui数据交给
WindowManagerService,WindowManagerService会将多个Surface数据合并成⼀整屏的ui数据,交给SurfaceFlinger渲染对应的Layer。⽽SurfaceView内部维护着⼀块Surface⽤于ui数据的的绘制,同时在WindowManagerService端会创建⼀个新的绘图对象,对应着SurfaceFlinger的⼀个新的Layer,因此SurfaceView中绘制的数据就由新的Layer,⽽不是宿主DecorView的Layer,意思就是SurfaceView有和宿主DecorView对应的ViewRootImpl⼀样的⼀套绘制渲染模型,两者分别独⽴渲染。
现在简单讲讲SurfaceView的⼯作流程。
1.在onAttachedToWindow中进⾏对SurfaceView的初始化和准备⼯作。完成透明区域的请求,获取WindowManagerService的本
地代理对象mSession,和对绘制的监听addOnPreDrawListener
2.在onWindowVisibilityChanged中将被显⽰时,调⽤updateWindow
3.updateWindow,初始化MyWindow对象,⽤于WindowManagerService通知SurfaceView的状态变化,layout以
请求WindowManagerService对Surface的UI进⾏布局,这样SurfaceFlinger就会为其创建⼀个独⽴的Layer绘图对象。这⾥同时会回调SurfaceHolder.Callback的surfaceCreated和surfaceChanged等⽅法,通知当前的SurfaceView是否准备好了。
4.然后我们就可以通过getHolder获取SurfaceHolder的对象,在新线程中,通过lockCanvas锁定画布,然后⽤Cavas对象进⾏绘
制,内部是通过SurfaceView的Surface对象来取得Canvas对象,该Canvas通过JNI调⽤到底层的Surface的Canvas进⾏操作。
5.在onDetachedFromWindow中进⾏对SurfaceView的清理⼯作。移除绘制监听,调⽤updateWindow通知回调
SurfaceHolder.Callback的surfaceDestroyed,mSession移除mWindow以使WindowManagerService解除对SurfaceView的操作。
再次总结,因为普通View⾛的是ViewRootImpl的绘制流程,在⾥⾯有对线程进⾏检查,⾮主线程的话会抛异常,⽬的就是实现单线程绘制模型,同时⼜要接受输⼊事情等。⽽SurfaceView有独⽴的绘制机制,⽐如独⽴的客户端Surface,WindowManagerService中独⽴的绘图对象,SurfaceFlinger中独⽴的Layer渲染。因为它⾥⾯可以只负责绘制,所以效率要更⾼。当然,SurfaceView的其他处理⽐如输⼊事件还是继承使⽤了View的那⼀套。
好了,简述完了之后,觉得还是有必要贴出些源码,让描述显得更加有依据⼀些。
public SurfaceView(Context context) {
super(context);
init();
}
public SurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);陪伴是最长情的告白
init();
}
public SurfaceView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
private void init() {
tWillNotDraw(true);
}
此处初始化,⽬的是不进⾏View的那⼀套绘制,专⼼做新线程的绘制。
@Override
protected void onAttachedToWindow() {
mSession = getWindowSession();
mLayout.tTitle("SurfaceView - " + getViewRootImpl().getTitle());
mViewVisibility = getVisibility() == VISIBLE;
if (!mGlobalListenersAdded) {
ViewTreeObrver obrver = getViewTreeObrver();
obrver.addOnScrollChangedListener(mScrollChangedListener);家常糖醋排骨
obrver.addOnPreDrawListener(mDrawListener);
mGlobalListenersAdded = true;
}
}
当SurfaceView被添加到Window上即将显⽰时,调⽤questTransparentRegion(this);请求顶层View给⾃⼰留出空⽩区域,这样我们的SurfaceView才能不会被其他View遮挡住。然后这⾥获取了WindowManager的代理对象,以后后⾯对WindowManager的请求操作。然后添加滚动监听和绘制监听
private final ViewTreeObrver.OnScrollChangedListener mScrollChangedListener
= new ViewTreeObrver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
updateWindow(fal, fal);
}
};
private final ViewTreeObrver.OnPreDrawListener mDrawListener =
new ViewTreeObrver.OnPreDrawListener() {
@Override
public boolean onPreDraw() {
/
/ reposition ourlves where the surface is
mHaveFrame = getWidth() > 0 && getHeight() > 0;
updateWindow(fal, fal);
return true;
}
};
这样,即将要绘制的时候,就会执⾏updateWindow⽅法了。
@Override
protected void onWindowVisibilityChanged(int visibility) {
mWindowVisibility = visibility == VISIBLE;
mRequestedVisible = mWindowVisibility && mViewVisibility;
updateWindow(fal, fal);
}
SurfaceView依附的Window要显⽰或隐藏时,也同样调⽤updateWindow,那updateWindow是做什么操作的呢?
protected void updateWindow(boolean force, boolean redrawNeeded) {
.....
final boolean creating = mWindow == null;
final boolean formatChanged = mFormat != mRequestedFormat;
final boolean sizeChanged = mWindowSpaceWidth != myWidth || mWindowSpaceHeight != myHeight;
final boolean visibleChanged = mVisible != mRequestedVisible;
final boolean layoutSizeChanged = getWidth() != mLayout.width
|| getHeight() != mLayout.height;
//此处判断SurfaceView是否有发⽣变化,需要更新
if (force || creating || formatChanged || sizeChanged || visibleChanged
|| mUpdateWindowNeeded || mReportDrawNeeded || redrawNeeded) {
//需要刷新SurfaceView,更新mLayout这个SurfaceView的LayoutParams的信息
......
if (mWindow == null) {
//MyWindow是⼀个Binder类,⽤于WindowMangerService通知回调SurfaceView,这⾥创建MyWindow对象mWIndow,并通过mSession.addToDisplay                Display display = getDisplay();
mWindow = new MyWindow(this);
mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
mVisible ? VISIBLE : GONE, DisplayId(), mContentInts,
mStableInts);
}
boolean realSizeChanged;
boolean reportDrawNeeded;
int relayoutResult;
//此处需要⽤锁锁住,防⽌其他线程同时修改
mSurfaceLock.lock();
try {
mUpdateWindowNeeded = fal;
先进个人推荐理由reportDrawNeeded = mReportDrawNeeded;
mReportDrawNeeded = fal;
mDrawingStopped = !visible;
//通过mSession这个binder对象请求WindowMangerService为SurfaceView的UI进⾏布局,然后WindowMangerService就会填充mNewSurface这个S                relayoutResult = layout(
mWindow, mWindow.mSeq, mLayout, mWindowSpaceWidth, mWindowSpaceHeight,
visible ? VISIBLE : GONE,
WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
mWinFrame, mOverscanInts, mContentInts,
mVisibleInts, mStableInts, mOutts, mBackdropFrame,
mConfiguration, mNewSurface);
if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
reportDrawNeeded = true;
}
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "New surface: " + mNewSurface
+ ", vis=" + visible + ", frame=" + mWinFrame);
mSurfaceFrame.left = 0;

if (mTranslator == null) {
mSurfaceFrame.right = mWinFrame.width();
mSurfaceFrame.bottom = mWinFrame.height();
} el {
float appInvertedScale = mTranslator.applicationInvertedScale;
mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
mSurfaceFrame.bottom = (int) (mWinFrame.height() * 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();
简单的魔术mSurfaceLock.unlock();
}
try {
redrawNeeded |= creating | reportDrawNeeded;
SurfaceHolder.Callback callbacks[] = null;
final boolean surfaceChanged = (relayoutResult
& WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED) != 0;
if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
mSurfaceCreated = fal;
if (mSurface.isValid()) {
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "visibleChanged -- surfaceDestroyed");
callbacks = getSurfaceCallbacks();
//这⾥判断了Surface被销毁了,回调实现了SurfaceHolder.Callback的对象,⼤部分情况就是我们继承实现的SurfaceView了
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceDestroyed(mSurfaceHolder);
}
}
}
//这⾥将最新状态的mNewSuface对象的数据更新到当前的mSurface中
if (visible && mSurface.isValid()) {
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
你瞒我瞒歌词mSurfaceCreated = true;
mIsCreating = true;
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "visibleChanged -- surfaceCreated");
if (callbacks == null) {
callbacks = getSurfaceCallbacks();分手后的祝福语
}
/
/这⾥判断了Surface被创建了,回调实现了SurfaceHolder.Callback的对象,⼤部分情况就是我们继承实现的SurfaceView了
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceCreated(mSurfaceHolder);
}
}
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();
}
//这⾥判断了Surface被更新了,回调实现了SurfaceHolder.Callback的对象,⼤部分情况就是我们继承实现的SurfaceView了
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();
}
//这⾥判断了Surface需要被重绘,回调实现了SurfaceHolder.Callback的对象,⼤部分情况就是我们继承实现的SurfaceView了
for (SurfaceHolder.Callback c : callbacks) {
if (c instanceof SurfaceHolder.Callback2) {
((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
mSurfaceHolder);
}
}
}
}
}
} finally {
mIsCreating = fal;
if (redrawNeeded) {
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "finishedDrawing");
mSession.finishDrawing(mWindow);
}
mSession.performDeferredDestroy(mWindow);
}
} catch (RemoteException ex) {
Log.e(TAG, "Exception from relayout", ex);
}
} el {
//除了以上情况,如果是SufaceView的位置或⼤⼩发⽣改变,就进⾏UI线程的布局更新
// Calculate the window position in ca RT los the window
// and we need to fallback to a UI-thread driven position update
getLocationInWindow(mLocation);
final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
|| mWindowSpaceTop != mLocation[1];
if (positionChanged || layoutSizeChanged) { // Only the position has changed
mWindowSpaceLeft = mLocation[0];
mWindowSpaceTop = mLocation[1];
// For our size changed check, we keep mLayout.width and mLayout.height
// in view local space.
mLocation[0] = mLayout.width = getWidth();
mLocation[1] = mLayout.height = getHeight();
transformFromViewToWindowSpace(mLocation);
mWinFrame.t(mWindowSpaceLeft, mWindowSpaceTop,
mLocation[0], mLocation[1]);
if (mTranslator != null) {
就业难
}
if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
try {
if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition UI, " +
"postion = [%d, %d, %d, %d]", System.identityHashCode(this),
mWinFrame.left, p,
mWinFrame.right, mWinFrame.bottom));
mWinFrame.right, mWinFrame.bottom, -1, mWinFrame);
} catch (RemoteException ex) {
Log.e(TAG, "Exception from relayout", ex);
}
}
}
}
}
可见,updateWindow的主要作⽤是SurfaceView更新的处理,包括mWindow,通知WindowMangerService中Surface的创建,还有Surface的创建,更新,销毁的通知回调等。
我们在看看MyWindow这个Binder类

本文发布于:2023-06-13 21:24:37,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/947668.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:绘制   对象   实现   情况   回调   数据   监听
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图