SurfaceView、GLSurfaceViewe\SurfaceTexture、TextureView、SurfaceHolder、Surface
一、简介
SurfaceTexture: SurfaceTexture是从Android3.0(API 11)加入的一个新类。这个类跟SurfaceView很像,可以从video decode里面获取图像流(image stream)。但是,和SurfaceView不同的是,SurfaceTexture在接收图像流之后,不需要显示出来。SurfaceTexture不需要显示到屏幕上,因此我们可以用SurfaceTexture接收来自decode出来的图像流,然后从SurfaceTexture中取得图像帧的拷贝进行处理,处理完毕后再送给另一个SurfaceView用于显示即可。
Surface: 处理被屏幕排序的原生的buffer,Android中的Surface就是一个用来画图形(graphics)或图像(image)的地方,对于View及其子类,都是画在Surface上,各Surface对象通过Surfaceflinger合成到frameBuffer,每个Surface都是双缓冲(实际上就是两个线程,一个渲染线程,一个UI更新线程),它有一个backBuffer和一个frontBuffer,Surface中创建了Canvas对象,用来管理Surface绘图操作,Canvas对应Bitmap,存储Surface中的内容(Surface可以理解成是用来管理Canvas画布的,而Canvas用来存储图像数据的)。
SurfaceView: 这个可能经常被说起,在Camera,MediaRecorder,MediaPlayer中用来显示图像的。SurfaceView是View的子类,且实现了Parcelable接口,其中内嵌了一个专门用于绘制的Surface,SurfaceView可以控制这个Surface的格式和尺寸,以及Surface的绘制位置。可以理解为**Surface就是管理数据的地方,SurfaceView就是展示数据的地方**。
SurfaceHolder:顾名思义,一个管理Surface的容器。SurfaceHolder是一个接口,可理解为一个Surface的监听器。
通过回调方法addCallback(SurfaceHolder.Callback callback )监听Surface的创建、改变、销毁等。通过获取Surface中的Canvas对象,并锁定所得到的Canvas对象,当修改Surface中的数据完成后,释放同步锁,并提交改变Surface的状态及图像,将新的图像数据进行展示。
而最后综合:SurfaceView中调用getHolder方法,可以获得当前SurfaceView中的Surface对应的SurfaceHolder,SurfaceHolder开始对Surface进行管理操作。这里其实按MVC模式理解的话,可以更好理解。M:Surface(图像数据),V:SurfaceView(图像展示),C:SurfaceHolder(图像数据管理)。
1、 SurfaceView
从Android 1.0(API level 1)时就有 。它继承自类View,因此它本质上是一个View。但与普通View不同的是,它有自己的Surface。我们知道,一般的Activity包含的多个View会组成View hierachy的树形结构,只有最顶层的DecorView,也就是根结点视图,才是对WMS可见的,这个DecorView在WMS中有一个对应的WindowState。相应地,在SF中对应的Layer。而SurfaceView自带一个Surface,这个Surface在WMS中有自己对应的WindowState,在SF中也会有自己的Layer。如下图所示:

也就是说, 虽然在Client端(App)它仍在View hierachy中,但在Server端(WMS和SF)中,它与宿主窗口是分离的(可以理解成其他的View在一个窗口中,SurfaceView中的Surface单独占用一个窗口)。这样的好处是**对这个Surface的渲染可以放到单独线程去做,渲染时可以有自己的GL context。这对于一些游戏、视频等性能相关的应用非常有益,因为它不会影响主线程对事件的响应。但它也有缺点,因为这个Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中,一些View中的特性也无法使用**。
通过源码发现,SurfaceView里面其实就是创建了一个Surface,Surface主要的实现就是管理里面的Canvas的打开、关闭等,以及监听这个Surface的创建、改变、销毁、锁定里面的Canvas以及解锁等操作的SurfaceHolder,以及一些使里面的Surface占用独立窗口的一些操作。
final Surface mSurface = new Surface(); // Current surface in use
/**
296 * Return the SurfaceHolder providing access and control over this
297 * SurfaceView's underlying surface.
298 *
299 * @return SurfaceHolder The holder of the surface.
300 */
301 public SurfaceHolder getHolder() {
302 return mSurfaceHolder;
303 }
304
@UnsupportedAppUsage
1616 private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
1617 private static final String LOG_TAG = "SurfaceHolder";
1618
1624 @Override
1625 public void addCallback(Callback callback) {
1626 synchronized (mCallbacks) {
1627 // This is a linear search, but in practice we'll
1628 // have only a couple callbacks, so it doesn't matter.
1629 if (!mCallbacks.contains(callback)) {
1630 mCallbacks.add(callback);
1631 }
1632 }
1633 }
1634
1635 @Override
1636 public void removeCallback(Callback callback) {
1637 synchronized (mCallbacks) {
1638 mCallbacks.remove(callback);
1639 }
1640 }
1641
1683
1684 /**
1685 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1686 *
1687 * After drawing into the provided {@link Canvas}, the caller must
1688 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1689 *
1690 * The caller must redraw the entire surface.
1691 * @return A canvas for drawing into the surface.
1692 */
1693 @Override
1694 public Canvas lockCanvas() {
1695 return internalLockCanvas(null, false);
1696 }
1697
1698 /**
1699 * Gets a {@link Canvas} for drawing into the SurfaceView's Surface
1700 *
1701 * After drawing into the provided {@link Canvas}, the caller must
1702 * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
1703 *
1704 * @param inOutDirty A rectangle that represents the dirty region that the caller wants
1705 * to redraw. This function may choose to expand the dirty rectangle if for example
1706 * the surface has been resized or if the previous contents of the surface were
1707 * not available. The caller must redraw the entire dirty region as represented
1708 * by the contents of the inOutDirty rectangle upon return from this function.
1709 * The caller may also pass <code>null</code> instead, in the case where the
1710 * entire surface should be redrawn.
1711 * @return A canvas for drawing into the surface.
1712 */
1713 @Override
1714 public Canvas lockCanvas(Rect inOutDirty) {
1715 return internalLockCanvas(inOutDirty, false);
1716 }
1717
1718 @Override
1719 public Canvas lockHardwareCanvas() {
1720 return internalLockCanvas(null, true);
1721 }
private void setWindowStopped(boolean stopped) {
310 mWindowStopped = stopped;
311 updateRequestedVisibility();
312 updateSurface();
313 }
314
315 @Override
316 protected void onAttachedToWindow() {
317 super.onAttachedToWindow();
318
319 getViewRootImpl().addSurfaceChangedCallback(this);
320 mWindowStopped = false;
321
322 mViewVisibility = getVisibility() == VISIBLE;
323 updateRequestedVisibility();
324
325 mAttachedToWindow = true;
326 mParent.requestTransparentRegion(SurfaceView.this);
327 if (!mGlobalListenersAdded) {
328 ViewTreeObserver observer = getViewTreeObserver();
329 observer.addOnScrollChangedListener(mScrollChangedListener);
330 observer.addOnPreDrawListener(mDrawListener);
331 mGlobalListenersAdded = true;
332 }
333 }
334
SurfaceView总结:里面会创建一个Surface,Surface主要管理Canvas画布对象的打开、关闭等操作,同时还有一个专门监听Surface创建、销毁、改变、里面的Canvas锁定等操作的SurfaceHolder,以及让Surface能够独占一个窗口的一系列操作。
2、GLSurfaceView
从Android 1.5(API level 3)开始加入,作为SurfaceView的补充。它可以看作是SurfaceView的一种典型使用模式。在SurfaceView的基础上,它加入了EGL的管理,并自带了渲染线程。另外它定义了用户需要实现的Render接口,提供了用Strategy pattern更改具体Render行为的灵活性。作为GLSurfaceView的Client,只需要将实现了渲染 函数的Renderer的实现类设置给GLSurfaceView即可。如:
public class TriangleActivity extends Activity { protected void onCreate(Bundle savedInstanceState) { mGLView = new GLSurfaceView(this); mGLView.setRenderer(new RendererImpl(this));
相关类图如下。其中SurfaceView中的SurfaceHolder主要是提供了一坨操作Surface的接口**。GLSurfaceView中的EglHelper和GLThread分别实现了上面提到的管理EGL环境和渲染线程的工作。GLSurfaceView的使用者需要实现Renderer接口**
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qQf7xFTw-1634811208136)(138a207fbab0b92008b7e5824d4758be.png)]](https://img-blog.csdnimg.cn/f31d63fa709c4f0db4006634a957859a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAd2VpeGluXzQ0NjY2MTcy,size_15,color_FFFFFF,t_70,g_se,x_16)
通过源码可知,GLSurfaceView继承至SurfaceView,同时实现了SurfaceHolder.CallBack2的接口,只是多添加了一个Renderer接口,以及GLThread渲染线程(主要执行渲染的相关工作,管理渲染器的执行操作等,比如设置渲染器的模式,请求获得Render渲染器等)和EGlHelper管理EGL环境的工作。
1921 private static final GLThreadManager sGLThreadManager = new GLThreadManager();
1922
1923 private final WeakReference<GLSurfaceView> mThisWeakRef =
1924 new WeakReference<GLSurfaceView>(this);
1925 @UnsupportedAppUsage
1926 private GLThread mGLThread;
1927 @UnsupportedAppUsage
1928 private Renderer mRenderer;
1929 private boolean mDetached;
1930 private EGLConfigChooser mEGLConfigChooser;
1931 private EGLContextFactory mEGLContextFactory;
1932 private EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
1933 private GLWrapper mGLWrapper;
设置Render渲染器之后,就可以创建GLThread渲染线程管理Render中一系列的操作了
/** @param renderer the renderer to use to perform OpenGL drawing.* 设置渲染器之后,马上开启渲染线程
347 */
348 public void setRenderer(Renderer renderer) {
349 checkRenderThreadState();
350 if (mEGLConfigChooser == null) {
351 mEGLConfigChooser = new SimpleEGLConfigChooser(true);
352 }
353 if (mEGLContextFactory == null) {
354 mEGLContextFactory = new DefaultContextFactory();
355 }
356 if (mEGLWindowSurfaceFactory == null) {
357 mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
358 }
359 mRenderer = renderer;
360 mGLThread = new GLThread(mThisWeakRef);
361 mGLThread.start();
362 }/**
606 * This method is used as part of the View class and is not normally
607 * called or subclassed by clients of GLSurfaceView.
608 */
609 @Override
610 protected void onAttachedToWindow() {
611 super.onAttachedToWindow();
612 if (LOG_ATTACH_DETACH) {
613 Log.d(TAG, "onAttachedToWindow reattach =" + mDetached);
614 }
615 if (mDetached && (mRenderer != null)) {
616 int renderMode = RENDERMODE_CONTINUOUSLY;
617 if (mGLThread != null) {
618 renderMode = mGLThread.getRenderMode();
619 }
620 mGLThread = new GLThread(mThisWeakRef);
621 if (renderMode != RENDERMODE_CONTINUOUSLY) {
622 mGLThread.setRenderMode(renderMode);
623 }
624 mGLThread.start();
625 }
626 mDetached = false;
627 }
管理EGL环境
public void setEGLConfigChooser(boolean needDepth) {
425 setEGLConfigChooser(new SimpleEGLConfigChooser(needDepth));
426 }
427
428 /**
429 * Install a config chooser which will choose a config
430 * with at least the specified depthSize and stencilSize,
431 * and exactly the specified redSize, greenSize, blueSize and alphaSize.
432 * <p>If this method is
433 * called, it must be called before {@link #setRenderer(Renderer)}
434 * is called.
435 * <p>
436 * If no setEGLConfigChooser method is called, then by default the
437 * view will choose an RGB_888 surface with a depth buffer depth of
438 * at least 16 bits.
439 *
440 */
441 public void setEGLConfigChooser(int redSize, int greenSize, int blueSize,
442 int alphaSize, int depthSize, int stencilSize) {
443 setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize,
444 blueSize, alphaSize, depthSize, stencilSize));
445 }
可以在GLThread渲染线程里面去请求它管理的Render渲染器,也可以设置Render的各种模式等
public void setRenderMode(int renderMode) {
495 mGLThread.setRenderMode(renderMode);
496 }
497
498 /**
499 * Get the current rendering mode. May be called
500 * from any thread. Must not be called before a renderer has been set.
501 * @return the current rendering mode.
502 * @see #RENDERMODE_CONTINUOUSLY
503 * @see #RENDERMODE_WHEN_DIRTY
504 */
505 public int getRenderMode() {
506 return mGLThread.getRenderMode();
507 }
508
509 /**
510 * Request that the renderer render a frame.
511 * This method is typically used when the render mode has been set to
512 * {@link #RENDERMODE_WHEN_DIRTY}, so that frames are only rendered on demand.
513 * May be called
514 * from any thread. Must not be called before a renderer has been set.
515 */
516 public void requestRender() {
517 mGLThread.requestRender();
518 }
519
520 /**
521 * This method is part of the SurfaceHolder.Callback interface, and is
522 * not normally called or subclassed by clients of GLSurfaceView.
523 */
524 public void surfaceCreated(SurfaceHolder holder) {
525 mGLThread.surfaceCreated();
526 }
527
528 /**
529 * This method is part of the SurfaceHolder.Callback interface, and is
530 * not normally called or subclassed by clients of GLSurfaceView.
531 */
532 public void surfaceDestroyed(SurfaceHolder holder) {
533 // Surface will be destroyed when we return
534 mGLThread.surfaceDestroyed();
535 }
536
537 /**
538 * This method is part of the SurfaceHolder.Callback interface, and is
539 * not normally called or subclassed by clients of GLSurfaceView.
540 */
541 public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
542 mGLThread.onWindowResize(w, h);
543 }
544
当Surface被创建、改变、绘制的时候会回调Render里面的方法
public interface Renderer {
710 /**
711 * Called when the surface is created or recreated.
733 */
734 void onSurfaceCreated(GL10 gl, EGLConfig config);
735
736 /**
737 * Called when the surface changed size.
753 * </pre>
754 * @param gl the GL interface. Use <code>instanceof</code> to
755 * test if the interface supports GL11 or higher interfaces.
756 * @param width
757 * @param height
758 */
759 void onSurfaceChanged(GL10 gl, int width, int height);
760
761 /**
762 * Called to draw the current frame.
763 * <p>
764 * This method is responsible for drawing the current frame.
765 * <p>
775 */
776 void onDrawFrame(GL10 gl);
777 }
778
EglHelper主要进行了一系列EGL环境的设置,以及创建、销毁Surface,GLThread中关于创建、销毁Surface等操作实际上就是调用了EglHelper中相应的方法等
private static class EglHelper {
1016 public EglHelper(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
1017 mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
1018 }
1019
1020 /**
1021 * Initialize EGL for a given configuration spec.
1022 * @param configSpec
1023 */
1024 public void start() {
1025 if (LOG_EGL) {
1026 Log.w("EglHelper", "start() tid=" + Thread.currentThread().getId());
1027 }
1028 /*
1029 * Get an EGL instance
1030 */
1031 mEgl = (EGL10) EGLContext.getEGL();
1032
1033 /*
1034 * Get to the default display.
1035 */
1036 mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
1037
1038 if (mEglDisplay == EGL10.EGL_NO_DISPLAY) {
1039 throw new RuntimeException("eglGetDisplay failed");
1040 }
1041
1042 /*
1043 * We can now initialize EGL for that display
1044 */
1045 int[] version = new int[2];
1046 if(!mEgl.eglInitialize(mEglDisplay, version)) {
1047 throw new RuntimeException("eglInitialize failed");
1048 }
1049 GLSurfaceView view = mGLSurfaceViewWeakRef.get();
1050 if (view == null) {
1051 mEglConfig = null;
1052 mEglContext = null;
1053 } else {
1054 mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
1055
1056 /*
1057 * Create an EGL context. We want to do this as rarely as we can, because an
1058 * EGL context is a somewhat heavy object.
1059 */
1060 mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
1061 }
1062 if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT) {
1063 mEglContext = null;
1064 throwEglException("createContext");
1065 }
1066 if (LOG_EGL) {
1067 Log.w("EglHelper", "createContext " + mEglContext + " tid=" + Thread.currentThread().getId());
1068 }
1069
1070 mEglSurface = null;
1071 }
1072
1073 /**
1074 * Create an egl surface for the current SurfaceHolder surface. If a surface
1075 * already exists, destroy it before creating the new surface.
1076 *
1077 * @return true if the surface was created successfully.
1078 */
1079 public boolean createSurface() {
1095
1096 /*
1097 * The window size has changed, so we need to create a new
1098 * surface.
1099 */
1100 destroySurfaceImp();
1101
1102 /*
1103 * Create an EGL surface we can render into.
1104 */
1105 GLSurfaceView view = mGLSurfaceViewWeakRef.get();
1106 if (view != null) {
1107 mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl,
1108 mEglDisplay, mEglConfig, view.getHolder());
1109 } else {
1110 mEglSurface = null;
1111 }
1112
1113 ...
1135 }private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
1235 EGL10 mEgl;
1236 EGLDisplay mEglDisplay;
1237 EGLSurface mEglSurface;
1238 EGLConfig mEglConfig;
1239 @UnsupportedAppUsage
1240 EGLContext mEglContext;
1163 }
GLThead渲染线程主要是管理Surface等渲染相关组件的创建与销毁,但是这个里面仅仅是进行了一些boolean值进行开关控制,真正实现具体的创建、销毁Surface等操作的实在EglHelper中,当Surface被创建等Render接口中的onSurfaceCreated()此时就能够监听得到这个事件,这也是为什么要在创建Render以后才开启GLThread线程。
static class GLThread extends Thread {
1254 GLThread(WeakReference<GLSurfaceView> glSurfaceViewWeakRef) {
1255 super();
1256 mWidth = 0;
1257 mHeight = 0;
1258 mRequestRender = true;
1259 mRenderMode = RENDERMODE_CONTINUOUSLY;
1260 mWantRenderNotification = false;
1261 mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
1262 }
1263
1264 @Override
1265 public void run() {
1266 setName("GLThread " + getId());
1267 if (LOG_THREADS) {
1268 Log.i("GLThread", "starting tid=" + getId());
1269 }
1270
1271 try {
1272 guardedRun();
1273 } catch (InterruptedException e) {
1274 // fall thru and exit normally
1275 } finally {
1276 sGLThreadManager.threadExiting(this);
1277 }
1278 }
1279
1280 /*
1281 * This private method should only be called inside a
1282 * synchronized(sGLThreadManager) block.
1283 */
1284 private void stopEglSurfaceLocked() {
1285 if (mHaveEglSurface) {
1286 mHaveEglSurface = false;
1287 mEglHelper.destroySurface();
1288 }
1289 }
1290
1291 /*
1292 * This private method should only be called inside a
1293 * synchronized(sGLThreadManager) block.
1294 */
1295 private void stopEglContextLocked() {
1296 if (mHaveEglContext) {
1297 mEglHelper.finish();
1298 mHaveEglContext = false;
1299 sGLThreadManager.releaseEglContextLocked(this);
1300 }
1301 }1839 private int mRenderMode;
1840 private boolean mRequestRender;
1841 private boolean mWantRenderNotification;
1842 private boolean mRenderComplete;
1843 private ArrayList<Runnable> mEventQueue = new ArrayList<Runnable>();
1844 private boolean mSizeChanged = true;
1845 private Runnable mFinishDrawingRunnable = null;
1846
1847 // End of member variables protected by the sGLThreadManager monitor.
1848
1849 @UnsupportedAppUsage
1850 private EglHelper mEglHelper;
1851
1852 /**
1853 * Set once at thread construction time, nulled out when the parent view is garbage
1854 * called. This weak reference allows the GLSurfaceView to be garbage collected while
1855 * the GLThread is still alive.
1856 */
1857 private WeakReference<GLSurfaceView> mGLSurfaceViewWeakRef;
GLSurfaceView总结:继承自SurfaceView,以及实现了SurfaceHolder.CallBack2里面的方法,也就是说就是SurfaceView的升级版,但不相同的是,里面多了一个GLThread渲染线程,用于主要执行渲染的相关工作,管理渲染器的执行操作等,比如设置渲染器的模式,请求获得Render渲染器等,和EGlHelper管理EGL环境的工作(需要注意:GLThead渲染线程主要是管理Surface等渲染相关组件的创建与销毁,但是这个里面仅仅是进行了一些boolean值进行开关控制,真正实现具体的创建、销毁Surface等操作的实在EglHelper中,当Surface被创建等Render接口中的onSurfaceCreated()此时就能够监听得到这个事件,这也是为什么要在创建Render以后才开启GLThread线程)。
3、SurfaceTexture
从Android 3.0(API level 11)加入。和SurfaceView不同的是, 它对图像流的处理并不直接显示,而是转为GL外部纹理,因此可用于图像流数据的二次处理(如Camera滤镜,桌面特效等)。比如Camera的预览数据,变成纹理后可以交给GLSurfaceView直接显示,也可以通过SurfaceTexture交给TextureView作为View heirachy中的一个硬件加速层来显示。首先,SurfaceTexture从图像流(来自Camera预览,视频解码,GL绘制场景等)中获得帧数据,当调用updateTexImage()时,根据内容流中最近的图像更新SurfaceTexture对应的GL纹理对象,接下来,就可以像操作普通GL纹理一样操作它了。从下面的类图中可以看出,它**核心管理着一个BufferQueue的Consumer和Producer两端。Producer端用于内容流的源输出数据,Consumer端用于拿GraphicBuffer并生成纹理。**SurfaceTexture.OnFrameAvailableListener用于让SurfaceTexture的使用者知道有新数据到来。JNISurfaceTextureContext是OnFrameAvailableListener从Native到Java的JNI跳板。其中SurfaceTexture中的attachToGLContext()和detachToGLContext()可以让多个GL context共享同一个内容源。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KBIWVlRR-1634811208137)(b3e32e098f31556b959e04ab97ed73b2.png)]](https://img-blog.csdnimg.cn/a156c899a4b54d3fabf16ca6496e3b08.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAd2VpeGluXzQ0NjY2MTcy,size_15,color_FFFFFF,t_70,g_se,x_16)
Android 5.0中将BufferQueue的核心功能分离出来,放在BufferQueueCore这个类中。BufferQueueProducer和BufferQueueConsumer分别是它的生产者和消费者实现基类(分别实现了IGraphicBufferProducer和IGraphicBufferConsumer接口)。它们都是由BufferQueue的静态 函数createBufferQueue()来创建的。Surface是生产者端的实现类,提供dequeueBuffer/queueBuffer等硬件渲染接口,和lockCanvas/unlockCanvasAndPost等软件渲染接口,其实Surface中的Canvas可以理解成就是一个存储图像数据的地方,使内容流的源可以往BufferQueue中填graphic buffer。GLConsumer继承自ConsumerBase,是消费者端的实现类。它在基类的基础上添加了GL相关的操作,如将graphic buffer中的内容转为GL纹理等操作。到此,以SurfaceTexture为中心的一个pipeline大体是这样的:
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iY678sYc-1634811208139)(0dc0f912534568bc141becf60ecf27b8.png)]](https://img-blog.csdnimg.cn/29e9ed74b07e4e3faa49b066f7880a02.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAd2VpeGluXzQ0NjY2MTcy,size_20,color_FFFFFF,t_70,g_se,x_16)
4、TextureView
在4.0(API level 14)中引入。它可以将内容流直接投影到View中,可以用于实现Live preview等功能。和SurfaceView不同, 它不会在WMS中单独创建窗口,而是作为View hierachy中的一个普通View,因此可以和其它普通View一样进行移动,旋转,缩放,动画等变化。值得注意的是 TextureView**必须在硬件加速的窗口中。它显示的内容流数据可以来自App进程或是远端进程。从类图中可以看到,TextureView继承自View,它与其它的View一样在View hierachy中管理与绘制。TextureView重载了draw()方法,其中主要把SurfaceTexture中收到的图像数据作为纹理更新到对应的HardwareLayer中**。SurfaceTexture.OnFrameAvailableListener用于通知TextureView内容流有新图像到来。SurfaceTextureListener接口用于让TextureView的使用者知道SurfaceTexture已准备好,这样就可以把SurfaceTexture交给相应的内容源。Surface为BufferQueue的Producer接口实现类,使生产者可以通过它的软件或硬件渲染接口为SurfaceTexture内部的BufferQueue提供graphic buffer。
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V1cx3Spl-1634811208139)(6ecbb1c888939556623ca7366558570d.png)]](https://img-blog.csdnimg.cn/9a68723c174a4650a6b1283dc3f00089.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAd2VpeGluXzQ0NjY2MTcy,size_20,color_FFFFFF,t_70,g_se,x_16)
TextureView内部就有一个SurfaceTexture,以及一个SurfaceTextureListener,用来监听SurfaceTexture的状态等,SurfaceTexture.onFrameAvailableListener主要用来通知TextureView有新图像的到来,TextureView重载了draw()方法,其中主要把SurfaceTexture中收到的图像数据作为纹理更新到对应的HardwareLayer中。
@UnsupportedAppUsage
115 private TextureLayer mLayer;
116 @UnsupportedAppUsage
117 private SurfaceTexture mSurface;
118 private SurfaceTextureListener mListener;
119 private boolean mHadSurface;
120
121 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
122 private boolean mOpaque = true;
123
124 private final Matrix mMatrix = new Matrix();
125 private boolean mMatrixChanged;
126
127 private final Object[] mLock = new Object[0];
128 private boolean mUpdateLayer;
129 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
130 private boolean mUpdateSurface;
131
132 private Canvas mCanvas;
public interface SurfaceTextureListener {
818 /**
819 * Invoked when a {@link TextureView}'s SurfaceTexture is ready for use.
820 *
821 * @param surface The surface returned by
822 * {@link android.view.TextureView#getSurfaceTexture()}
823 * @param width The width of the surface
824 * @param height The height of the surface
825 */
826 void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height);
827
828 /**
829 * Invoked when the {@link SurfaceTexture}'s buffers size changed.
830 *
831 * @param surface The surface returned by
832 * {@link android.view.TextureView#getSurfaceTexture()}
833 * @param width The new width of the surface
834 * @param height The new height of the surface
835 */
836 void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height);
837
838 /**
839 * Invoked when the specified {@link SurfaceTexture} is about to be destroyed.
840 * If returns true, no rendering should happen inside the surface texture after this method
841 * is invoked. If returns false, the client needs to call {@link SurfaceTexture#release()}.
842 * Most applications should return true.
843 *
844 * @param surface The surface about to be destroyed
845 */
846 boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface);
847
848 /**
849 * Invoked when the specified {@link SurfaceTexture} is updated through
850 * {@link SurfaceTexture#updateTexImage()}.
851 *
852 * @param surface The surface just updated
853 */
854 void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface);
855 }
@Override
342 public final void draw(Canvas canvas) {
343 // NOTE: Maintain this carefully (see View#draw)
344 mPrivateFlags = (mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
345
346 /* Simplify drawing to guarantee the layer is the only thing drawn - so e.g. no background,
347 scrolling, or fading edges. This guarantees all drawing is in the layer, so drawing
348 properties (alpha, layer paint) affect all of the content of a TextureView. */
349
350 if (canvas.isHardwareAccelerated()) {
351 RecordingCanvas recordingCanvas = (RecordingCanvas) canvas;
352
353 TextureLayer layer = getTextureLayer();
354 if (layer != null) {
355 applyUpdate();
356 applyTransformMatrix();
357
358 mLayer.setLayerPaint(mLayerPaint); // ensure layer paint is up to date
359 recordingCanvas.drawTextureLayer(layer);
360 }
361 }
362 }TextureLayer getTextureLayer() {
387 if (mLayer == null) {
388 if (mAttachInfo == null || mAttachInfo.mThreadedRenderer == null) {
389 return null;
390 }
391
392 mLayer = mAttachInfo.mThreadedRenderer.createTextureLayer();
393 boolean createNewSurface = (mSurface == null);
394 if (createNewSurface) {
395 // Create a new SurfaceTexture for the layer.
396 mSurface = new SurfaceTexture(false);
397 nCreateNativeWindow(mSurface);
398 }
399 mLayer.setSurfaceTexture(mSurface);
400 mSurface.setDefaultBufferSize(getWidth(), getHeight());
401 mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler);
402
403 if (mListener != null && createNewSurface) {
404 mListener.onSurfaceTextureAvailable(mSurface, getWidth(), getHeight());
405 }
406 mLayer.setLayerPaint(mLayerPaint);
407 }
408
409 if (mUpdateSurface) {
410 // Someone has requested that we use a specific SurfaceTexture, so
411 // tell mLayer about it and set the SurfaceTexture to use the
412 // current view size.
413 mUpdateSurface = false;
414
415 // Since we are updating the layer, force an update to ensure its
416 // parameters are correct (width, height, transform, etc.)
417 updateLayer();
418 mMatrixChanged = true;
419
420 mLayer.setSurfaceTexture(mSurface);
421 mSurface.setDefaultBufferSize(getWidth(), getHeight());
422 }
423
424 return mLayer;
425 }
public @Nullable Canvas lockCanvas(@Nullable Rect dirty) {
688 if (!isAvailable()) return null;
689
690 if (mCanvas == null) {
691 mCanvas = new Canvas();
692 }
693
694 synchronized (mNativeWindowLock) {
695 if (!nLockCanvas(mNativeWindow, mCanvas, dirty)) {
696 return null;
697 }
698 }
699 mSaveCount = mCanvas.save();
700
701 return mCanvas;
702 }
二、总结
SurfaceView是一个有自己独立Surface的View, 它的渲染可以放在单独线程而不是主线程中, 其缺点是不能做变形和动画。
SurfaceTexture可以用作非直接输出的内容流,这样就提供二次处理的机会。与SurfaceView直接输出相比,这样会有若干帧的延迟。同时,由于它本身管理BufferQueue,因此 内存消耗也会稍微大一些。
TextureView是一个可以把内容流作为外部纹理输出在上面的View, 它本身需要是一个硬件加速层。
事实上TextureView本身也包含了SurfaceTexture, 它与SurfaceView+SurfaceTexture组合相比可以完成类似的功能(即把内容流上的图像转成纹理,然后输出), 区别在于TextureView是在View hierachy中做绘制,因此一般它是在主线程上做的(在Android 5.0引入渲染线程后,它是在渲染线程中做的)。而SurfaceView+SurfaceTexture在单独的Surface上做绘制,可以是用户提供的线程,而不是系统的主线程或是渲染线程。另外,与SurfaceView相比,它还有个好处是可以用Hardware overlay进行显示。

















