[关闭]
@natsumi 2018-04-30T16:17:03.000000Z 字数 9526 阅读 1592

Android图形系统之Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的联系

Android


  1. /**
  2. * author:conowen@大钟
  3. * E-mail:conowen@hotmail.com
  4. * http://blog.csdn.net/conowen
  5. * 注:本文为原创,仅作为学习交流使用,转载请标明作者及出处。
  6. * 转载注:修改了部分翻译 删去了部分比较基础的内容
  7. **/

Surface

  1. Surface
  2. extends Object
  3. implements Parcelable

Class Overview

Handle onto a raw buffer that is being managed by the screen compositor.

简单翻译:
Surface是原始图像缓冲区(raw buffer)的一个句柄,而原始图像缓冲区是由屏幕图像合成器(screen compositor)管理的。

就如在C语言编程一样,通过一个文件的句柄,就可以操作文件,获取文件的内容。同样的,通过Surface就可以获取raw buffer其中的内容。原生缓冲区(raw buffer)存储着当前窗口的像素数据。

事实上,当得到一个Surface对象时,同时会得到一个Canvas(画布)对象。这一点可以通过查看\frameworks\base\core\java\android\view\Surface.java文件可知道Surface类定义了一个Canvas成员变量

  1. //@\frameworks\base\core\java\android\view\Surface.java
  2. // The mSurfaceControl will only be present for Surfaces used by the window
  3. // server or system processes. When this class is parceled we defer to the
  4. // mSurfaceControl to do the parceling. Otherwise we parcel the
  5. // mNativeSurface.
  6. private int mSurfaceControl;
  7. private int mSaveCount;
  8. private Canvas mCanvas;
  9. private int mNativeSurface;
  10. private int mSurfaceGenerationId;
  11. private String mName;

理解Canvas对象,可以把它当做画布,Canvas的方法大多数是设置画布的大小、形状、画布背景颜色等等,要想在画布上面画画,一般要与Paint对象结合使用,顾名思义,Paint就是画笔的风格,颜料的色彩之类的。

  1. Paint paint = new Paint();// 创建画笔
  2. paint.setColor(Color.RED);// 设置红色
  3. canvas.drawCircle(60, 20, 10, paint);// 画一个圆

Surface本身的作用类似一个句柄,得到了这个句柄就可以得到其中的Canvas、原生缓冲器以及其它方面的内容。

Surface实现了Parcelable接口,(implements Parcelable),也就是说Surface对象可以把显示内容的数据写入到 Parcel 中,并且能够从Parcel读回数据。

SurfaceView

  1. SurfaceView
  2. extends View
  3. java.lang.Object

直接子类: GLSurfaceView, RSSurfaceView, VideoView

Class Overview

Provides a dedicated drawing surface embedded inside of a view hierarchy. You can control the format of this surface and, if you like, its size; the SurfaceView takes care of placing the surface at the correct location on the screen

SurfaceView提供了一个专门用于绘制的surface,这个surface内嵌于View层级。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface在屏幕的正确绘制位置。

The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed. The view hierarchy will take care of correctly compositing with the Surface any siblings of the SurfaceView that would normally appear on top of it. This can be used to place overlays such as buttons on top of the Surface, though note however that it can have an impact on performance since a full alpha-blended composite will be performed each time the Surface changes.

surface 是 Z-ordered 的(也就是说在 xyz 坐标系中,按照Z坐标排序的,Z值大的表面覆盖在Z值小的表面的上方),这表明它总在它的 SurfaceView 所在窗口的后面。SurfaceView 在其所在的窗口中打了一个洞,让 Surface 露出来,才能看到 Surface 里面的内容。可以放置一些覆盖图层(overlays)在Surface上面,如Button、Textview之类的。但是,需要注意的是,如果Surface上面有全透明的控件,那么随着Surface的每一次变化,这些全透明的控件就会重新渲染,这样的话,就影响性能与显示的效果。

Access to the underlying surface is provided via the SurfaceHolder interface, which can be retrieved by calling getHolder().

你可以通过SurfaceHolder这个接口去访问Surface,而执行getHolder()方法可以得到SurfaceHolder接口。

The Surface will be created for you while the SurfaceView's window is visible; you should implementsurfaceCreated(SurfaceHolder) andsurfaceDestroyed(SurfaceHolder) to discover when the Surface is created and destroyed as the window is shown and hidden.

当SurfaceView的窗口可见时,Surface就会被创建,当SurfaceView窗口隐藏时,Surface就会被销毁。当然了,你也可以通过覆盖surfaceCreated(SurfaceHolder) 和 surfaceDestroyed(SurfaceHolder) 这两个方法来验证一下Surface何时被创建与何时被销毁。

One of the purposes of this class is to provide a surface in which a secondary thread can render into the screen. If you are going to use it this way, you need to be aware of some threading semantics:

这个类可以为渲染线程(非UI线程)提供一个可用于渲染屏幕的Surface,若你要用这种方式更新屏幕,你需要了解以下线程知识:

All SurfaceView and SurfaceHolder.Callback methods will be called from the thread running the SurfaceView's window (typically the main thread of the application). They thus need to correctly synchronize with any state that is also touched by the drawing thread.

所有SurfaceView 和 SurfaceHolder.Callback 的方法都应该在主线程(UI线程)里面调用,应该要确保渲染线程所访问变量的同步性。

You must ensure that the drawing thread only touches the underlying Surface while it is valid -- betweenSurfaceHolder.Callback.surfaceCreated() andSurfaceHolder.Callback.surfaceDestroyed().

你必须确保只有当 Surface 有效的时候,才能让渲染进程访问
——也就是当Surface的生命周期在SurfaceHolder.Callback.surfaceCreated() 和SurfaceHolder.Callback.surfaceDestroyed()之间

SurfaceView与Surface的联系

简单来说,SurfaceView与Surface的联系就是,Surface是管理显示内容的数据(implementsParcelable),包括存储于数据的交换。而SurfaceView就是把这些数据显示出来到屏幕上面。

SurfaceHolder

  1. android.view.SurfaceHolder

Class Overview

Abstract interface to someone holding a display surface. Allows you to control the surface size and format, edit the pixels in the surface, and monitor changes to the surface. This interface is typically available through theSurfaceView class.

SurfaceHolder 是控制 surface 的一个抽象接口,你可以通过 SurfaceHolder 来控制 surface 的尺寸和格式,或者修改 surface 的像素,监视 surface 的变化等等,SurfaceHolder 是 SurfaceView 的典型接口。

When using this interface from a thread other than the one running its SurfaceView, you will want to carefully read the methods lockCanvas() and Callback.surfaceCreated().

与直接控制 SurfaceView 来修改 surface 不同,在非UI线程(原文是非运行 SurfaceView 的线程)使用 SurfaceHolder 来修改 surface 时,需要注意 lockCanvas() 和 Callback.surfaceCreated() 这两个方法。

SurfaceHolder 控制 surface 流程的几个方法

  1. // Add a Callback interface for this holder.
  2. // 给SurfaceHolder一个回调对象。
  3. abstract void addCallback(SurfaceHolder.Callback callback)
  4. // Just like lockCanvas() but allows specification of a dirty rectangle.
  5. // 锁定画布中的某一个区域,返回的画布对象 Canvas (当更新的内容只有一个区域时,同时要追求高效,可以只更新一部分的区域,而不必更新全部画布区域)
  6. abstract Canvas lockCanvas(Rect dirty)
  7. // Start editing the pixels in the surface.
  8. // 锁定画布,返回的画布对象 Canvas
  9. abstract Canvas lockCanvas()
  10. // Removes a previously added Callback interface from this holder.
  11. // 移除回调对象
  12. abstract void removeCallback(SurfaceHolder.Callback callback)
  13. // Finish editing pixels in the surface.
  14. // 结束锁定画图,并提交改变。
  15. abstract void unlockCanvasAndPost(Canvas canvas)

SurfaceHolder.Callback

  1. android.view.SurfaceHolder.Callback

非直接子类:GLSurfaceView,NativeActivity,RSSurfaceView,SurfaceHolder.Callback2

Class Overview

A client may implement this interface to receive information about changes to the surface. When used with a SurfaceView, the Surface being held is only available between calls to surfaceCreated(SurfaceHolder) and surfaceDestroyed(SurfaceHolder). The Callback is set with SurfaceHolder.addCallback method.

简单翻译:

SurfaceHolder.Callback 是监听 surface 变化的一个接口。如果是和一个 SurfaceView 一起使用则 Surface 只在 surfaceCreated(SurfaceHolder) 到 surfaceDestroyed(SurfaceHolder) 之间有效。通过 SurfaceHolder.addCallback 方法添加回调。

  1. /**
  2. * This is called immediately after the surface is first created.
  3. * Implementations of this should start up whatever rendering code
  4. * they desire. Note that only one thread can ever draw into
  5. * a {@link Surface}, so you should not draw into the Surface here
  6. * if your normal rendering will be in another thread.
  7. *
  8. * @param holder The SurfaceHolder whose surface is being created.
  9. */
  10. // 在surface创建时被调用,一般在这个方法里面开启渲染屏幕的线程。
  11. public void surfaceCreated(SurfaceHolder holder);
  12. /**
  13. * This is called immediately after any structural changes (format or
  14. * size) have been made to the surface. You should at this point update
  15. * the imagery in the surface. This method is always called at least
  16. * once, after {@link #surfaceCreated}.
  17. *
  18. * @param holder The SurfaceHolder whose surface has changed.
  19. * @param format The new PixelFormat of the surface.
  20. * @param width The new width of the surface.
  21. * @param height The new height of the surface.
  22. */
  23. // surface发生改变时被调用
  24. public void surfaceChanged(SurfaceHolder holder, int format, int width,
  25. int height);
  26. /**
  27. * This is called immediately before a surface is being destroyed. After
  28. * returning from this call, you should no longer try to access this
  29. * surface. If you have a rendering thread that directly accesses
  30. * the surface, you must ensure that thread is no longer touching the
  31. * Surface before returning from this function.
  32. *
  33. * @param holder The SurfaceHolder whose surface is being destroyed.
  34. */
  35. // 销毁时被调用,一般在这个方法里将渲染的线程停止
  36. public void surfaceDestroyed(SurfaceHolder holder);
  37. }

附上上述所说几种的联系方法

  1. SurfaceHolder = SurfaceView.getHolder();
  2. Surface = SurfaceHolder.getSurface();
  3. Canvas = SurfaceHolder.LockCanvas(Rect dirty)
  4. Canvas = Surface.lockCanvas(Rect dirty)

Demo 小程序

共有两个 class 效果图如下,具体看代码和注释。

效果图:

此处输入图片的描述

  1. import android.os.Bundle;
  2. import android.support.v7.app.AppCompatActivity;
  3. public class MainActivity extends AppCompatActivity {
  4. @Override
  5. protected void onCreate(Bundle savedInstanceState) {
  6. super.onCreate(savedInstanceState);
  7. setContentView(new MySurfaceView(this));
  8. // setContentView(R.layout.activity_main);
  9. }
  10. }
  1. import android.content.Context;
  2. import android.graphics.Canvas;
  3. import android.graphics.Color;
  4. import android.graphics.Paint;
  5. import android.graphics.Rect;
  6. import android.util.Log;
  7. import android.view.SurfaceHolder;
  8. import android.view.SurfaceView;
  9. /**
  10. * @SurfaceViewDemoActivity.java
  11. * author: conowen
  12. * e-mail: conowen@hotmail.com
  13. * date : 2012.8.4
  14. */
  15. public class MySurfaceView extends SurfaceView implements
  16. SurfaceHolder.Callback {
  17. private String TAG = "conowen";
  18. private SurfaceHolder sfh;
  19. private boolean ThreadFlag;
  20. private int counter;
  21. private Canvas canvas;
  22. private Thread mThread = new Thread(new Runnable() {
  23. @Override
  24. public void run() {
  25. // TODO Auto-generated method stub
  26. while (ThreadFlag) {
  27. // 锁定画布,得到Canvas对象
  28. canvas = sfh.lockCanvas();
  29. // 设定Canvas对象的背景颜色
  30. canvas.drawColor(Color.GREEN);
  31. // 创建画笔
  32. Paint p = new Paint();
  33. // 设置画笔颜色
  34. p.setColor(Color.RED);
  35. // 设置文字大小
  36. p.setTextSize(40);
  37. // 创建一个Rect对象rect
  38. // public Rect (int left, int top, int right, int bottom)
  39. Rect rect = new Rect(100, 50, 400, 350);
  40. // 在canvas上绘制rect
  41. canvas.drawRect(rect, p);
  42. // 在canvas上显示时间
  43. // public void drawText (String text, float x, float y, Paint
  44. // paint)
  45. canvas.drawText("时间 = " + (counter++) + " 秒", 500, 200, p);
  46. if (canvas != null) {
  47. // 解除锁定,并提交修改内容,更新屏幕
  48. sfh.unlockCanvasAndPost(canvas);
  49. }
  50. try {
  51. Thread.sleep(1000);
  52. } catch (InterruptedException e) {
  53. // TODO Auto-generated catch block
  54. e.printStackTrace();
  55. }
  56. }
  57. }
  58. });
  59. public MySurfaceView(Context context) {
  60. super(context);
  61. // TODO Auto-generated constructor stub
  62. // 通过SurfaceView获得SurfaceHolder对象
  63. sfh = this.getHolder();
  64. // 为SurfaceHolder添加回调结构SurfaceHolder.Callback
  65. sfh.addCallback(this);
  66. }
  67. @Override
  68. public void surfaceChanged(SurfaceHolder holder, int format, int width,
  69. int height) {
  70. // TODO Auto-generated method stub
  71. Log.i(TAG, "surfaceChanged");
  72. }
  73. @Override
  74. public void surfaceCreated(SurfaceHolder holder) {
  75. // TODO Auto-generated method stub
  76. Log.i(TAG, "surfaceCreated");
  77. counter = 0;
  78. ThreadFlag = true;
  79. mThread.start();
  80. }
  81. @Override
  82. public void surfaceDestroyed(SurfaceHolder holder) {
  83. // TODO Auto-generated method stub
  84. Log.i(TAG, "surfaceDestroyed");
  85. ThreadFlag = false;
  86. }
  87. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注