TextureView与SurfaceView

https://blog.csdn.net/holmofy/article/details/66578852
https://blog.csdn.net/Holmofy/article/details/66583879
http://chriszeng87.iteye.com/blog/2219159

SurfaceView和TextureView均继承于android.view.View,与其它View不同的是,两者都能在独立的线程中绘制和渲染,在专用的GPU线程中大大提高渲染的性能。
SurfaceView可以通过SurfaceHolder.addCallback方法在子线程中更新UI,TextureView则可以通过TextureView.setSurfaceTextureListener在子线程中更新UI。
对于一些类似于坦克大战等需要不断告诉更新画布的游戏来说,SurfaceView绝对是极好的选择。但是比如视频播放器或相机应用的开发,TextureView则更加适合。

一、SurfaceView

SurfaceView从Android 1.0(API level 1)时就有。它继承自类View,因此它本质上是一个View。但与普通View不同的时,它有自己的Surface。我们知道,一般的Activity包含的多个View会组成View hierachy的树形结构,只有最顶层的DecorView,也就是根结点视图,才是对WMS(WindowManagerService)可见的。这个DecorView在WMS中有一个对应的WindowState。相应地,在SF(SurfaceFlinger)中对应的Layer。而SurfaceView自带一个Surface,这个Surface在WMS中有自己对应的WindowState,在SF中也会有自己的Layer。如下图所示:
在这里插入图片描述
也就是说,虽然在App端它仍在View hierachy中,但在Server端(WMS和SF)中,它与宿主窗口是分离的。这样的好处是对这个Surface的渲染可以放到单独线程去做,渲染时可以有自己的GL context。这对于一些游戏、视频等性能相关的应用非常有益,因为它不会影响主线程对事件的响应。但它也有缺点,因为这个Surface不在View hierachy中,它的显示也不受View的属性控制,所以不能进行平移,缩放等变换,也不能放在其它ViewGroup中,一些View中的特性也无法使用。

SurfaceView专门提供了嵌入视图层级的绘制界面,开发者可以控制该界面像Size等的形式,能保证界面在屏幕上的正确位置。但也有局限:

  • 是独立的一层View,更像是独立的一个Window,不能加上动画、评议、缩放;
  • 两个SurfaceView不能互相覆盖

SurfaceView的工作方式是创建一个置于应用窗口之后的新窗口。这种方式的效率非常高,因为SurfaceView窗口刷新的时候不需要重绘应用程序的窗口(android普通窗口的视图绘制机制是一层一层的,任何一个子元素或者是局部的刷新都会导致整个视图结构全部重绘一次,因此效率非常低下)。
可以用SurfaceHold接口访问SurfaceView本身内嵌的Surface。当SurfaceView变得可见时,surface被创建;当SurfaceView隐藏时,surface被销毁。
SurfaceView封装了一个Surface对象,而不是Canvas。这一点很重要,因为Surface可以使用后台线程绘制。对于那些资源敏感的操作,或者那些要求快速更新或者高速帧率的地方,例如使用3D图形,创建游戏,或者实时预览摄像头,这一点特别有用。
SurfaceView、SurfaceHolderSurface的关系可以概括为以下几点:

-SurfaceView是拥有独立绘图层的特殊View
-Surface就是指SurfaceView所拥有的那个绘图层,其实它就是内存中的一段绘图缓冲区
-SurfaceView中具有两个Surface,也就是我们所说的双缓冲机制
-SurfaceHolder顾名思义就是Surface的持有者,SurfaceView就是通过过SurfaceHolder来对Surface进行管理控制的。并且SurfaceView.getHolder方法可以获取SurfaceView相应的SurfaceHolder。
-Surface是在SurfaceView所在的Window可见的时候创建的。我们可以使用SurfaceHolder.addCallback方法来监听Surface的创建与销毁的事件。

因为SurfaceView的内容不在应用窗口上,所以不能使用变换(平移、缩放、旋转等)。也难以放在ListView或者ScrollView中,不能使用UI控件的一些特性比如View.setAlpha()。

为了解决这个问题Android 4.0中引入了TextureView。

二、TextureView

TextureView在4.0(API level 14)中引入,它可以将内容流直接投影到View中,用于实现Live preview等功能。内容流可以来自本应用程序以及其他进程。

TextureView在使用的时候涉及到这么几个类:SurfaceTextureSurface
Surface就是SurfaceView中使用的Surface,就是内存中的一段绘图缓冲区。
SurfaceTexture是什么呢,官方文档给出的解释是这样的:

SurfaceTexture用来捕获视频流中的图像帧的,视频流可以是相机预览或者视频解码数据。SurfaceTexture可以作为android.hardware.camera2, MediaCodec, MediaPlayer, 和 Allocation这些类的目标视频数据输出对象。可以调用updateTexImage()方法从视频流数据中更新当前帧,这就使得视频流中的某些帧可以跳过。

TextureView可以通过getSurfaceTexture()方法来获取TextureView相应的SurfaceTexture。但是最好的方式还是使用TextureView.SurfaceTextureListener监听器来对SurfaceTexture的创建和销毁进行监听,因为getSurfaceTexture可能获取的是空对象

与SurfaceView相比,TextureView不会在WMS中创建单独的窗口,而是作为View hierachy中的一个普通View,这使得它可以像一般的View一样执行一些变换操作,比如移动、缩放、旋转、动画等等,例如,你可以通过调用myView.setAlpha(0.5f)将TextureView设置成半透明(0为透明,1为不透明)。
另外,TextureView必须在硬件加速开启的窗口中。
TextureView的使用非常简单,你唯一要做的就是获取用于渲染内容的SurfaceTexture。具体做法是先创建TextureView对象,然后实现SurfaceTextureListener接口,代码如下:

public class MainActivity extends Activity implements SurfaceTextureListener{
protected void onCreate(Bundle savedInstanceState) {
   myTexture = new TextureView(this);
   myTexture.setSurfaceTextureListener(this);
   setContentView(myTexture);
   }
}

Activity implements了SurfaceTextureListener接口因此activity中需要重写如下方法:

    @Override
    public void onSurfaceTextureAvailable(SurfaceTexture arg0, int arg1, int arg2) {
    }
    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture arg0) {
    }
    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture arg0, int arg1,int arg2) {
    }
    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture arg0) {
    }

TextureView可以使用setAlpha和setRotation方法达到改变透明度和旋转的效果。

    myTexture.setAlpha(1.0f);
    myTexture.setRotation(90.0f);

除了上面的方法之外,TextureView还有如下方法:
这里写图片描述

TextureView重载了draw()方法,其中主要把SurfaceTexture中受到的图像数据作为纹理更新到对应的HandwareLayer中。SurfaceTexture.OnFrameAvailableListener用于通知TextureView内容流有新图像到来。SurfaceTextureListener接口用于让TextureView的使用者知道SurfaceTexture已准备好,这样就可以把SurfaceTexture交给相应的内容源。Surface为BufferQueue的Producer接口实现类,使生产者可以通过它的软件或硬件渲染接口为SurfaceTexture内部的BufferQueue提供graphic buffer。

总结

简单地说,SurfaceView是一个有自己Surface的View。它的渲染可以放在单独线程而不是主线程中。其缺点是不能做变形和动画。SurfaceTexture可以用作非直接输出的内容流,这样就提供二次处理的机会。与SurfaceView直接输出相比,这样会有若干帧的延迟。同时,由于它本身管理BufferQueue,因此内存消耗也会稍微大一些。TextureView是一个可以把内容流作为外部纹理输出在上面的View。它本身需要是一个硬件加速层。事实上TextureView本身也包含了SurfaceTexture。它与SurfaceView+SurfaceTexture组合相比可以完成类似的功能(即把内容流上的图像转成纹理,然后输出)。区别在于TextureView是在View hierachy中做绘制,因此一般它是在主线程上做的(在Android 5.0引入渲染线程后,它是在渲染线程中做的)。而SurfaceView+SurfaceTexture在单独的Surface上做绘制,可以是用户提供的线程,而不是系统的主线程或是渲染线程。另外,与TextureView相比,它还有个好处是可以用Hardware overlay进行显示。

猜你喜欢

转载自blog.csdn.net/zjpp2580369/article/details/82745589