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接口**