最近准备研究cocos2d,所以先记录下SurfaceView学习笔记。

先看看官方API文档对SurfaceView的描述:
https://developer.android.com/reference/android/view/SurfaceView.html

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

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.

The transparent region that makes the surface visible is based on the layout positions in the view hierarchy. If the post-layout transform properties are used to draw a sibling view on top of the SurfaceView, the view may not be properly composited with the surface.

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

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

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:

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.

You must ensure that the drawing thread only touches the underlying Surface while it is valid – between
SurfaceHolder.Callback.surfaceCreated() and
SurfaceHolder.Callback.surfaceDestroyed().

由于全段过长,我只加粗了重点部分。
简单来说,要使用SurfaceView,需要两个线程:

  • 主线程(即UI线程):用于接受用户操作输入
  • 第二线程(secondary thread):用于渲染界面

那么我们首先创建一个SurfaceUI类(extends SurfaceView)作为界面。

public class SurfaceUI extends SurfaceView{    public SurfaceUI(Context context) {        super(context);    }}

修改MainActivity的setContentView:

public class MainActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        SurfaceUI surfaceUI = new SurfaceUI(this);        setContentView(surfaceUI);    }}

接下来我们需要使用SurfaceHolder,一样先看看官方API文档:

https://developer.android.com/reference/android/view/SurfaceHolder.html

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 the SurfaceView class.

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().

发现SurfaceHolder是个抽象接口,在它的内部类中找到SurfaceHolder.Callback

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接口,修改SurfaceUI 实现SurfaceHolder.Callback接口并且实现未实现方法:

public class SurfaceUI extends SurfaceView implements SurfaceHolder.Callback{    public SurfaceUI(Context context) {        super(context);    }    @Override    public void surfaceCreated(SurfaceHolder holder) {    }    @Override    public void surfaceChanged(SurfaceHolder holder, int format, int width,            int height) {    }    @Override    public void surfaceDestroyed(SurfaceHolder holder) {    }}

接下来根据说明,可以获取SurfaceHolder和添加回调:

    public SurfaceUI(Context context) {        super(context);        SurfaceHolder surfaceHolder = getHolder();//获取SurfaceHolder        surfaceHolder.addCallback(this);//为SurfaceHolder添加回调    }

有了SurfaceView和SurfaceHolder,现在只缺第二线程了,也就是渲染线程,在SurfaceUI类中创建内部线程类:

    /** * 用于渲染的第二线程 */    public class RenderThread extends Thread {        @Override        public void run() {            super.run();        }    }

接下来就是注意,调用渲染线程必须在surfaceCreated(SurfaceHolder) and surfaceDestroyed(SurfaceHolder)之间,这个在API文档中多次出现。
那么的话首先定义一个flag:

    /** * 用于控制是否渲染界面 */    private boolean isRender = true;

在surfaceCreated中开启渲染线程,surfaceDestroyed中停止渲染:

    @Override    public void surfaceCreated(SurfaceHolder holder) {        new RenderThread().start();//开始渲染线程    }    @Override    public void surfaceDestroyed(SurfaceHolder holder) {        isRender = false;//停止渲染    }

上述都完成后,就剩下如何操作渲染线程了。
其实SurfaceView和SurfaceHolder都是操作Surface(可以在源码中找到),可以在Surface的源码中看到一段:(还记得官方API上面写的you will want to carefully read the methods lockCanvas()吗)

    /** draw into a surface */    public Canvas lockCanvas(Rect dirty) throws OutOfResourcesException, IllegalArgumentException {        /* * the dirty rectangle may be expanded to the surface's size, if for * instance it has been resized or if the bits were lost, since the last * call. */        return lockCanvasNative(dirty);    }

可以看到上述的代码中的注释就是说,这是用来绘制界面的,既然有lock,一般就有对应的unlock方法,在此方法的源码下面可以看到两个方法:

  /** unlock the surface and asks a page flip */    public native   void unlockCanvasAndPost(Canvas canvas);    /** * unlock the surface. the screen won't be updated until * post() or postAll() is called */    public native   void unlockCanvas(Canvas canvas);

可以看到unlockCanvas不会更新界面,直到调用post或者postAll方法,所以提供了另一个方法unlockCanvasAndPost。
但是上述方法都是Surface本身的,我们实际使用的SurfaceView,所以SurfaceHolder中也有对应的方法:

    public Canvas lockCanvas();    public Canvas lockCanvas(Rect dirty);    public void unlockCanvasAndPost(Canvas canvas);

不过要注意的是,SurfaceHolder的lockCanvas上的锁和Surface中上的锁不是同一把锁,使用SurfaceHolder的lockCanvas相当于上了2次锁
所以可以在渲染线程中分三步完成渲染:

//1.lockCanvasCanvas lockCanvas = surfaceHolder.lockCanvas();//2.绘制界面(可以做其他复杂操作)lockCanvas.drawRGB(255, 0, 0);//3.unlock and postsurfaceHolder.unlockCanvasAndPost(lockCanvas);

运行效果如下:

完整代码

SurfaceUI

public class SurfaceUI extends SurfaceView implements SurfaceHolder.Callback{    /** * 用于控制是否渲染界面 */    private boolean isRender = true;    private SurfaceHolder surfaceHolder;    public SurfaceUI(Context context) {        super(context);        surfaceHolder = getHolder();        surfaceHolder.addCallback(this);//为SurfaceHolder添加回调    }    @Override    public void surfaceChanged(SurfaceHolder holder, int format, int width,            int height) {    }    @Override    public void surfaceCreated(SurfaceHolder holder) {        new RenderThread().start();//开始渲染线程    }    @Override    public void surfaceDestroyed(SurfaceHolder holder) {        isRender = false;//停止渲染    }    /** * 用于渲染的第二线程 */    public class RenderThread extends Thread {        @Override        public void run() {            while (isRender) {                //1.lockCanvas                Canvas lockCanvas = surfaceHolder.lockCanvas();                //2.绘制界面(可以做其他复杂操作)                lockCanvas.drawRGB(255, 0, 0);                //3.unlock and post                surfaceHolder.unlockCanvasAndPost(lockCanvas);            }        }    }}

MainActivity

public class MainActivity extends Activity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        SurfaceUI surfaceUI = new SurfaceUI(this);        setContentView(surfaceUI);    }}

声明

原创文章,欢迎转载,请保留出处。有任何错误、疑问或者建议,欢迎指出。我的邮箱:Maxwell_nc@163.com

更多相关文章

  1. Android使用httpPost向服务器发送请求的方法
  2. 设置图片缩放方法失效 解决办法设置android:scaleType属性
  3. XAMARIN Android获取WIFIMAC地址的方法
  4. 实时获取Android 各版本电量的统一方法
  5. 利用浏览器默认方法获取浏览器当前位置
  6. 【Android】实现Activity页面暂停几秒后跳转的两种方法
  7. android实现图片圆角化实现三种方法
  8. “android list targets 无target显示” 的解决方法。

随机推荐

  1. android的单元测试摘要
  2. Android和JAVA面试题相关资料
  3. mono for android 获取手机照片或拍照并
  4. Android(安卓)获取设备信息
  5. eclipse ADT在线安装 https://dl-ssl.goo
  6. android 监听去电实现ip拨号 广播接收者
  7. 【Android(安卓)view】获取状态栏高度sta
  8. android测试器
  9. Android(安卓)9Patch图片
  10. Android(安卓)学习