认识 SurfaceView

[java] view plain copy

  1.   

SurfaceView是基于View视图进行扩展的视图类,适用于2D游戏开发,主要特点有:

【1】surfaceView中对于画布的重绘是由一个新的线程去绘制,因此可以处理一些耗时的操作

【2】surfaceView具有双重缓冲机制(view没有)

适用于动态实时更新的画面,比如游戏处理中就算主角啥事不做,旁边流水会动,飞行射击类,抽奖转盘的制作都是动态,需要不断的绘制元素状态,通常view更加适合被动更新的如棋牌类

1、SurfaceView基本框架

SurfaceView使用也比较好掌握,基本框架见如下代码:

[java] view plain copy

  1. /** 
  2.  *  
  3.  * @author ELVIS 
  4.  *surfaceView 常用编写模式 
  5.  */  
  6. public class SurfaceViewTemplate extends SurfaceView implements Callback, Runnable {  
  7.     private SurfaceHolder mHolder;  
  8.     private Canvas mCanvas;  
  9.   
  10.     private Thread t;// 用于绘制的子线程  
  11.     private boolean isRunning; // 线程的控制开关  
  12.   
  13.     public SurfaceViewTemplate(Context context) {  
  14.         this(context, null);  
  15.         // TODO Auto-generated constructor stub  
  16.     }  
  17.   
  18.     public SurfaceViewTemplate(Context context, AttributeSet attrs) {  
  19.         super(context, attrs);  
  20.   
  21.         mHolder = getHolder();  
  22.         mHolder.addCallback(this); // 添加回调结构  
  23.   
  24.         setFocusable(true);// 可获得焦点  
  25.         setFocusableInTouchMode(true);  
  26.         setKeepScreenOn(true);// 设置常亮  
  27.   
  28.     }  
  29.   
  30.     @Override  
  31.     public void surfaceCreated(SurfaceHolder holder) {  
  32.         // TODO Auto-generated method stub  
  33.         isRunning = true;  
  34.         t = new Thread(this);  
  35.   
  36.     }  
  37.   
  38.     @Override  
  39.     public void surfaceChanged(SurfaceHolder holder, int format, int width,  
  40.             int height) {  
  41.         // TODO Auto-generated method stub  
  42.   
  43.     }  
  44.   
  45.     @Override  
  46.     public void surfaceDestroyed(SurfaceHolder holder) {  
  47.         // TODO Auto-generated method stub  
  48.         isRunning = false;  
  49.   
  50.     }  
  51.   
  52.     @Override  
  53.     public void run() {  
  54.         // TODO Auto-generated method stub  
  55.         while(isRunning){  
  56.             draw();//进行绘制  
  57.         }  
  58.     }  
  59.   
  60.     private void draw() {  
  61.         //获取canvas  
  62.         try {  
  63.             mCanvas = mHolder.lockCanvas();  
  64.             if(mCanvas!=null){  
  65.                 //draw   
  66.             }  
  67.         } catch (Exception e) {  
  68.             /*// TODO Auto-generated catch block 
  69.             e.printStackTrace();*/  
  70.         }  
  71.         finally{  
  72.             //canvas 释放  
  73.             if(mCanvas!=null){  
  74.                 mHolder.unlockCanvasAndPost(mCanvas);  
  75.             }  
  76.         }  
  77.           
  78.     }  
  79.   
  80. }  

这里做一些补充解释

【1】继承SurfaceView

【2】重要的SurfaceHolder,此类提供控制SurfaceView的大小,格式等等,并且监听其状态,因而实现Callback接口重写函数

SurfaceCreated:当surfaceView创建完成时响应的函数

surfaceChanged:当surfaceView状态发生改变时候响应函数

surfaceDetroy:当surfaceView状态摧毁时响应函数

【3】由于surfaceView不同于view,前者需要一个线程来完成更新,框架都差不多,不同的只是draw里面的东西复杂度(这里是核心)

【4】SurfaceView是通过SurfaceHolder来修改其数据,所以在SurfaceView上不再通过onDraw来绘图,而是通过surfaceHolder取到surfaceView的canvas,然后再进行绘制

因此即使重写view的ondraw函数在SurfaceView启动时也不会执行到

【5】在进行绘制的时候一般都是lockCanvas获取canvas同时对画布进行加锁,与之对应的还有unlockCanvasAndPost函数用于解锁画布和提交

2、刷屏方式

这里也是跟view绘图的区别所在。在view绘图中,View类本身提供俩种重绘函数(invalidate和postInvalidate),其内部已经封装了对画布的刷屏操作,所以每次在ondraw中重绘画布永远看不到之前绘制过的图形,但是在SurfaceView是自定义的绘制函数,而且每次获取到的canvas仍然是上次的画布,因此在使用surfaceView视图时,得到画布canvas之后首先做的事刷屏操作,否则界面状态是无法更新的,这点千万要留意

一般刷屏有以下几种方式

(1)每次绘图前,绘制一个等同于屏幕大小的图形覆盖在画布上面

(2)没次绘图前在此画布上填充一种颜色

(3)每次绘图前指定RGB来填充画布

[java] view plain copy

  1. public void myDraw(){  
  2.         Canvas canvas = mHolder.lockCanvas();  
  3.         //绘制矩形  
  4.         canvas.drawRect(0, 0,this.getWidth(),this.getHeight(),paint);  
  5.         //canvas.drawColor(Color.BLACK);//画布填充颜色  
  6.         //canvas.drawRGB(0, 0, 0);//指定RGB来填充颜色  
  7.           
  8.         canvas.drawText("surfaceViewTest", textX, textY, paint);  
  9.         mHolder.unlockCanvasAndPost(canvas);  
  10.     }  

3、surfaceVAiew 添加线程的一些要点

3.1线程

在上面也说过了,surfaceView靠自己的线程去绘制画布以及游戏逻辑,往往需要一个线程标志位 boolean flag,主要有以下两点说明

【1】便于消亡线程

线程启动就会执行其run函数,run函数结束后线程随之消亡。在游戏开发中使用的线程一般都会在run函数中使用一个while死循环,在其中来执行绘图或者其他逻辑,如果游戏暂停或者结束,为了便于销毁线程需要设置一个标志位来控制

【2】防止重复创建线程及程序异常

主要涉及到back和home操作

按back时的surfaceView状态变化 surfaceDestroyed——构造函数——surfaceCreated——surfaceChanged

按home时的surfaceView状态变化 surfaceDestroyed——surfaceCreated——surfaceChanged

即按back键视图会被重新加载,而且千万不要把线程初始化放在surfaceCreate之前否则玩家点击home,再回到游戏就会抛出异常,这是从home恢复时会直接进入surfaceCreate再次启动线程

通俗做法:线程的初始化和线程的启动都写在视图的surfaceCreateed创建函数中,并且将线程的标志位flag在视图摧毁的时候置为fasle,这样既可以避免“线程已经启动“的异常,还可以避免点击back按键无线增加线程数目的问题

3.2 刷新帧时间尽可能保持一致

一般是通过系统函数获取到一个时间戳start;处理函数之后再次获取一个时间戳end,假设游戏线程的休眠时间为X,则按照如下房事编写

[java] view plain copy

  1. if((end-start)<X){  
  2.     Thread.sleep(X-(end-start));  
  3. }  

最后用一串显示hello world代码来总结一下

[java] view plain copy

  1. public class MySurfaceView extends SurfaceView implements Callback, Runnable {  
  2.     // 用于控制surfacView  
  3.     private SurfaceHolder mHolder;  
  4.     // 声明一个画笔  
  5.     private Paint paint;  
  6.     // 文本的坐标  
  7.     private int textX = 10, textY = 10;  
  8.     // 声明一个线程  
  9.     private Thread th;  
  10.     // 线程消亡的标志位  
  11.     private boolean flag;  
  12.     // 声明一个画布  
  13.     private Canvas canvas;  
  14.     // 声明屏幕的宽高  
  15.     private int screenW, screenH;  
  16.   
  17.     public MySurfaceView(Context context) {  
  18.         super(context);  
  19.         // 实例化mHolder  
  20.         mHolder = this.getHolder();  
  21.         // 为surfaceView添加监听器  
  22.         mHolder.addCallback(this);  
  23.         // 实例化画笔  
  24.         paint = new Paint();  
  25.         // 实例化画笔颜色为白色  
  26.         paint.setColor(Color.WHITE);  
  27.         // 设置焦点  
  28.         setFocusable(true);  
  29.     }  
  30.   
  31.     @Override  
  32.     public void surfaceCreated(SurfaceHolder holder) {  
  33.         screenW = this.getWidth();  
  34.         screenH = this.getHeight();  
  35.         flag = true;  
  36.         // 实例化线程  
  37.         th = new Thread(this);  
  38.         // 启动线程  
  39.         th.start();  
  40.     }  
  41.   
  42.     @Override  
  43.     public void surfaceChanged(SurfaceHolder holder, int format, int width,  
  44.             int height) {  
  45.         // TODO Auto-generated method stub  
  46.   
  47.     }  
  48.   
  49.     @Override  
  50.     public void surfaceDestroyed(SurfaceHolder holder) {  
  51.         flag = true;  
  52.   
  53.     }  
  54.   
  55.     @Override  
  56.     public void run() {  
  57.         while (flag) {  
  58.             long start = System.currentTimeMillis();  
  59.             myDraw();  
  60.             logic();  
  61.             long end = System.currentTimeMillis();  
  62.             try {  
  63.                 if (end - start < 50) {  
  64.                     Thread.sleep(50 - (end - start));  
  65.                 }  
  66.             } catch (InterruptedException e) {  
  67.                 // TODO Auto-generated catch block  
  68.                 e.printStackTrace();  
  69.             }  
  70.         }  
  71.   
  72.     }  
  73.  <pre name="code" class="java">       /* 游戏处理逻辑 */  
  74.     private void logic() {  
  75.         // 处理游戏逻辑部分  
  76.   
  77.     }  
  78.   
  79.     private void myDraw() {  
  80.         try {  
  81.             canvas = mHolder.lockCanvas();  
  82.             if (canvas != null) {  
  83.                 // 这里采用绘制矩形方式刷屏  
  84.                 // 绘制矩形  
  85.                 canvas.drawRect(0, 0, this.getWidth(), this.getHeight(), paint);  
  86.                 canvas.drawText("Hello World", textX, textY, paint);  
  87.             }  
  88.         } catch (Exception e) {  
  89.   
  90.         } finally {  
  91.             if (canvas != null)  
  92.                 mHolder.unlockCanvasAndPost(canvas);  
  93.         }  
  94.   
  95.     }  
  96.   
  97.     @Override  
  98.     public boolean onTouchEvent(MotionEvent event) {  
  99.         textX = (int) event.getX();  
  100.         textY = (int) event.getY();  
  101.         return true;  
  102.     }  
  103.   
  104.     @Override  
  105.     public boolean onKeyDown(int keyCode, KeyEvent event) {  
  106.         return super.onKeyDown(keyCode, event);  
  107.     }  
  108.       
  109.   
  110. }  

转载:http://blog.csdn.net/xsf50717/article/details/48676919

时间: 2024-11-03 07:14:45

认识 SurfaceView的相关文章

surfaceview 循环播放视频用视频缩略图代替视频切换时的样式 怎么操作嗯

问题描述 surfaceview 循环播放视频用视频缩略图代替视频切换时的样式 怎么操作嗯 surfaceview 循环播放视频用视频缩略图代替视频切换时的样式 怎么操作嗯

在android中用surfaceview播放视频时,实现未播放的预览效果?

问题描述 在android中用surfaceview播放视频时,实现未播放的预览效果? 在android中用surfaceview播放视频时,如何在surfaceview的出现时就加载视频的第一帧,实现未播放的预览效果? 类似于图的那种效果,谁有什么解决方法吗? 解决方案 http://download.csdn.net/detail/ohbxiaoxin/8320741 两个控件叠加,至于预览的图片,需要事先从视频中提取出来.

android技巧:SurfaceView的制作android游戏框架介绍

1.介绍 我们知道android游戏主要包含两方面.一方面是控制类,这个通过一些循环以及监听机制来实现.另一方面就是显示类.在现实类中最常见的就是view,view的机制比较适合刷新比较慢的应用,像是象棋之类的.本文要提到的SurfaceView是继承自view类.surfaceview的好处是可以随意控制对象的位置,大小等属性,最关键是的提供了SurfaceHolder类,使用getHolder方法获取,相关的有Canvas lockCanvas() .下面就来介绍下surfaceview的结

Android SurfaceView游戏开发示例

当我们需要开发一个复杂游戏的时候,而且对程序的执行效率要求很高时,View类就不能满足需求了,这时必须用 SurfaceView类进行开发. 例如,对速度要求很高的游戏时,View类就不能满足需求了,这时必须使用SurfaceView类进 行开发.例如,对速度要求很高的游戏,可以使用双缓冲来显示.游戏中的背景.人物.动画等都需要绘制在一个画布(Canvas) 上,而SurfaceView可以直接访问一个画布,SurfaceView 是提供给需要直接画像素而不是使用窗体部件的应用使用的. 每个 S

Android SurfaceView学习示例

SurfaceView是View的子类,使用的方式与任何View所派生的类都是完全相同的,可以像其他View那样应用动画,并把它们放 到布局中. SurfaceView封装的Surface支持使用本章前面所描述的所有标准Canvas方法进行绘图,同时也支持完全的OpenGL ES库. 使用OpenGL,你可以再Surface上绘制任何支持的2D或者3D对象,与在2D画布上模拟相同的效果相比,这种方法可以依 靠硬件加速(可用的时候)来极大地提高性能. 对于显示动态的3D图像来说,例如,那些使用Go

Android SurfaceView的运用

下面就贴上一个小程序代码,主要运用SurfaceView来实现在屏幕上画一个圆,你可以通过按方向键和触摸屏幕来改变圆的位 置 代码: Activity package com.view; import android.app.Activity; import android.os.Bundle; import android.view.Window; import android.view.WindowManager; public class MainActivity extends Acti

Android开发之SurfaceView显示动画效果

一.基础知识: SurfaceView继承自View,View负责在主线程中更新动画,而SurfaceView是在一个新线程中更新动画. SurfaceView类的主要方法: // 在SurfaceView创建时调用 pubilic abstract void surfaceCreated(SurfaceHolder holder) // 在SurfaceView改变时调用 pubilic abstract void surfaceChanged(SurfaceHolder holder, in

surfaceview-安卓继承SurfaceView重写surfaceCreated 怎么找不到

问题描述 安卓继承SurfaceView重写surfaceCreated 怎么找不到 解决方案 surfaceCreated 是callback接口的,不是surfaceview的

android使用MediaPlayer和SurfaceView播放视频怎样设置按原始比例播放

问题描述 android使用MediaPlayer和SurfaceView播放视频怎样设置按原始比例播放 现在的情况是,视频大小总是铺满SurfaceView,怎样可以在SurfaceView中按照视频本身的比例播放呢 解决方案 surfaceview 本身就是按比例显示视频的啊 . . . .看你代码 和布局是什么样的

SurfaceView调用camera进行显示与拍照

1.首先继承SurfaceView并实现SurfaceHolder.Callback接口使用接口的原因:因为使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始(Surface-表面,这个概念在 图形编程中常常被提到.基本上我们可以把它当作显存的一个映射,写入到Surface 的内容                      可以被直接复制到显存从而显示出来,这使得显示速度会非常快),而在Surface 被销毁之前必须结束.所以Callback 中的s