SurfaceView、GLSurfaceView、SurfaceTexture、TextureView、SurfaceHolder、Surface

article/2025/10/28 19:14:49

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接口,其中内嵌了一个专门用于绘制的SurfaceSurfaceView可以控制这个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)]

通过源码可知,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)]


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)]


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)]


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进行显示。


http://chatgpt.dhexx.cn/article/21ovlIfH.shtml

相关文章

android之通过SurfaceView以及SurfaceHolder进行视频播放

使用AudioView进行视频播放的时候&#xff0c;是不是很不爽&#xff0c;千篇一律的模式&#xff0c;恶心吧。这里&#xff0c;我们可以通过一些方式对MediaPlayer进行包装。而所用到的正是SurfaceView以及SurfaceHolder。 最终效果图&#xff1a; 我们提供了四个按钮&#xff…

ANativeWindow 和 Surface

Android播放视频从解码到显示实质也是BufferQueue的生产消费的过程&#xff0c;如下图所示&#xff1a; 其中生产者是Surface&#xff0c;消费者是SurfaceFlinger。 本文主要针对Surface进行分析&#xff0c;理清ANativeWindow 和 Surface之间的关系。 ANativeWindow的定义如…

Android之Surface 与 SurfaceFlinger关系

通过前面的知识我们知道了&#xff0c;Android 系统从按下开机键到桌面&#xff0c;从桌面点击 App 图标到 Activity 显示的过程。但是 Activity 是怎么显示在屏幕上的呢&#xff1f;下面我们就来讨论下这一过程。 SurfaceFlinger 启动过程 SurfaceFlinger 进程是由 init 进程…

SurfaceView、SurfaceHolder与Surface

相关文章 SurfaceView、SurfaceHolder与SurfaceTextureView、SurfaceTexture与Surface 按照官方文档的说法&#xff0c;SurfaceView继承自View&#xff0c;并提供了一个独立的绘图层&#xff0c;你可以完全控制这个绘图层&#xff0c;比如说设定它的大小&#xff0c;所以Surf…

surfaceView、surface和sufaceHolder的关系

surfaceView、surface和sufaceHolder的关系 1.SurfaceView与Surface的联系2.SurfaceView3.Surface4.SurfaceHolder 1.SurfaceView与Surface的联系 简单来说&#xff0c;Surface是管理显示内容的数据&#xff08;implementsParcelable&#xff09;&#xff0c;包括存储于数据的…

线程天敌TerminateThread与SuspendThread http://blog.csdn.net/magictong/article/details/6304439

线程天敌TerminateThread与SuspendThread 标签&#xff1a; thread null delete dll c user 2011-04-06 13:22 10295人阅读 评论(1) 收藏 举报 分类&#xff1a; C Win32&#xff08;93&#xff09; 版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得…

511遇见易语言API模块线程挂起(SuspendThread)

线程挂起用到的API是SuspendThread 511遇见易语言模块API教程 API 暂停指定的线程 函数功能&#xff1a; 挂起线程。 参数&#xff1a; 第1个参数&#xff1a; HANDLE hThread 线程句柄。 返回值&#xff1a; 成功&#xff1a;线程的前一个挂起数。 失败&#xff1a;-1。 …

面向对象设计6大原则

概览 单一职责 1、单一职责 Single Responsibility Principle&#xff0c;简称是SRP。SRP的英文定义是&#xff1a; There should never be more than one reason for a class to change. 翻译过来的意思是&#xff1a; 应该有且仅有一个原因引起类的变更。 或许我们可以…

带你了解面向对象的设计原则

##一 摘要 今天晚上给大家介绍一下面向对象的设计原则,为什么要介绍这个呢,原因很简单,大家平时所接触的语言,无论是object-C,C,JavaScrpt,C#等都是属于面向对象语言,既然是面向对象设计语言,那么就有必要去了解一下面向对象的设计原则.那么面向对象的设计原则有哪些呢?今天来…

面向对象七大设计原则

面向对象设计的七大原则 前言 在软件开发中&#xff0c;为了提高软件系统的可维护性和可复用性&#xff0c;增加软件的可扩展性和灵活性&#xff0c;我们能要尽量根据 7 条原则来开发程序&#xff0c;从而提高软件开发效率、节约软件开发成本和维护成本。 面向对象设计原则概…

软件设计与体系——面向对象设计的原则

一&#xff1a;前言 用一道题熟悉OO设计与编程&#xff1a;给定一个4位数&#xff08;数字不完全相同&#xff09;&#xff0c;这4个数字可以得到最大4位数和最小4位数&#xff0c;算它们的差&#xff0c;不是6174则重复上述过程&#xff0c;最终会得到6174&#xff0c;验证这…

面向对象设计七大原则

面向对象设计七大原则 1) 开-闭原则 &#xff08;Open Closed Principle&#xff0c;OCP&#xff09;定义开闭原则的作用实现方法例子其它例子代码 2) 里氏代换原则&#xff08;Liskov Substitutiion Principle&#xff0c;LSP&#xff09;定义作用实现方法例子 3) 依赖倒置原则…

面向对象设计六大原则

6大原则如下&#xff1a; 1)单一职责原则,一个合理的类&#xff0c;应该仅有一个引起它变化的原因&#xff0c;即单一职责,就是设计的这个类功能应该只有一个; 优点&#xff1a;消除耦合&#xff0c;减小因需求变化引起代码僵化。 2) 开-闭原则&#xff0c;讲的是设计要对扩展…

设计模式(三)——面向对象设计原则

设计模式需要遵循基本的软件设计原则。可维护性(Maintainability)和可复用性(Reusability)是衡量软件质量的重要的两个属性: 可维护性:软件能够被理解、改正、适应及扩展的难易程度可复用性:软件能够被复用的难易程度面向对象设计的原则是支持可维护性复用,一方面需要实…

程序员必备的七大面向对象设计原则(一)

花絮 每天都在和面向对象打交道&#xff0c;但是我们在应用面向对象的时候感觉自己的面向对象技术应用的很合理&#xff1f;理解的很到位&#xff1f;应用的很到位&#xff1f;用的时候恰到好处&#xff1f;用的是否符合软件的发展趋势&#xff1f; 上面很多一连串的问题&#…

面向对象设计原则之开闭原则

开闭原则是面向对象的可复用设计的第一块基石&#xff0c;它是最重要的面向对象设计原则。开闭原则由Bertrand Meyer于1988年提出&#xff0c;其定义如下&#xff1a; 开闭原则(Open-Closed Principle, OCP)&#xff1a;一个软件实体应当对扩展开放&#xff0c;对修改关闭。即…

面向对象设计模式5大基本原则

“宇宙万物之中,没有一样东西能像思想那么顽固。” 一爱默生 首先明确模式是针对面向对象的&#xff0c;它的三大特性&#xff0c;封装、继承、多态。 面向对象设计模式有5大基本原则&#xff1a;单一职责原则、开发封闭原则、依赖倒置原则、接口隔离原则、Liskov替换原…

面向对象六大设计原则

目录 1 、单一职责&#xff08;Single Responsibility Principle&#xff09; 2 、开闭原则&#xff08;Open Close Principle&#xff09; 3、里氏替换原则&#xff08;Liskov Substitution Principle&#xff09; 4、接口隔离原则&#xff08;Interface Segregation Prin…

阿里巴巴编码规范解读(六、七)-工程结构及设计规约

工程结构 应用分层 1.【推荐】 图中默认上层依赖于下层&#xff0c;箭头关系表示可直接依赖&#xff0c;如&#xff1a;开放接口层可以依赖于 Web层&#xff0c;也可以直接依赖于 Service层&#xff0c;依此类推。 开放接口层&#xff1a;可直接封装 Service 方法暴露成RPC…