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

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

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

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

1、SurfaceView基本框架

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

/**
 *
 * @author ELVIS
 *surfaceView 常用编写模式
 */
public class SurfaceViewTemplate extends SurfaceView implements Callback, Runnable {
	private SurfaceHolder mHolder;
	private Canvas mCanvas;

	private Thread t;// 用于绘制的子线程
	private boolean isRunning; // 线程的控制开关

	public SurfaceViewTemplate(Context context) {
		this(context, null);
		// TODO Auto-generated constructor stub
	}

	public SurfaceViewTemplate(Context context, AttributeSet attrs) {
		super(context, attrs);

		mHolder = getHolder();
		mHolder.addCallback(this); // 添加回调结构

		setFocusable(true);// 可获得焦点
		setFocusableInTouchMode(true);
		setKeepScreenOn(true);// 设置常亮

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		isRunning = true;
		t = new Thread(this);

	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub

	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		// TODO Auto-generated method stub
		isRunning = false;

	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while(isRunning){
			draw();//进行绘制
		}
	}

	private void draw() {
		//获取canvas
		try {
			mCanvas = mHolder.lockCanvas();
			if(mCanvas!=null){
				//draw
			}
		} catch (Exception e) {
			/*// TODO Auto-generated catch block
			e.printStackTrace();*/
		}
		finally{
			//canvas 释放
			if(mCanvas!=null){
				mHolder.unlockCanvasAndPost(mCanvas);
			}
		}

	}

}

这里做一些补充解释

【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来填充画布

public void myDraw(){
		Canvas canvas = mHolder.lockCanvas();
		//绘制矩形
		canvas.drawRect(0, 0,this.getWidth(),this.getHeight(),paint);
		//canvas.drawColor(Color.BLACK);//画布填充颜色
		//canvas.drawRGB(0, 0, 0);//指定RGB来填充颜色

		canvas.drawText("surfaceViewTest", textX, textY, paint);
		mHolder.unlockCanvasAndPost(canvas);
	}

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,则按照如下房事编写

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

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

public class MySurfaceView extends SurfaceView implements Callback, Runnable {
	// 用于控制surfacView
	private SurfaceHolder mHolder;
	// 声明一个画笔
	private Paint paint;
	// 文本的坐标
	private int textX = 10, textY = 10;
	// 声明一个线程
	private Thread th;
	// 线程消亡的标志位
	private boolean flag;
	// 声明一个画布
	private Canvas canvas;
	// 声明屏幕的宽高
	private int screenW, screenH;

	public MySurfaceView(Context context) {
		super(context);
		// 实例化mHolder
		mHolder = this.getHolder();
		// 为surfaceView添加监听器
		mHolder.addCallback(this);
		// 实例化画笔
		paint = new Paint();
		// 实例化画笔颜色为白色
		paint.setColor(Color.WHITE);
		// 设置焦点
		setFocusable(true);
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		screenW = this.getWidth();
		screenH = this.getHeight();
		flag = true;
		// 实例化线程
		th = new Thread(this);
		// 启动线程
		th.start();
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		// TODO Auto-generated method stub

	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		flag = true;

	}

	@Override
	public void run() {
		while (flag) {
			long start = System.currentTimeMillis();
			myDraw();
			logic();
			long end = System.currentTimeMillis();
			try {
				if (end - start < 50) {
					Thread.sleep(50 - (end - start));
				}
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}
 <pre name="code" class="java">       /* 游戏处理逻辑 */
	private void logic() {
		// 处理游戏逻辑部分

	}

	private void myDraw() {
		try {
			canvas = mHolder.lockCanvas();
			if (canvas != null) {
				// 这里采用绘制矩形方式刷屏
				// 绘制矩形
				canvas.drawRect(0, 0, this.getWidth(), this.getHeight(), paint);
				canvas.drawText("Hello World", textX, textY, paint);
			}
		} catch (Exception e) {

		} finally {
			if (canvas != null)
				mHolder.unlockCanvasAndPost(canvas);
		}

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		textX = (int) event.getX();
		textY = (int) event.getY();
		return true;
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		return super.onKeyDown(keyCode, event);
	}

}
												

认识 SurfaceView的更多相关文章

  1. SurfaceView 绘制分形图

    之前一直做的是应用类,这次抽时间,参考网上资料实践了下SurfaceView.目标是在页面上画一个科赫曲线的分形图. 代码如下: package com.example.fredric.demo02; ...

  2. Android中surface,surfaceview,sufaceholder以及surface客户端的关系

    这里以照相机camera功能的实现来解释surface,surfaceview,sufaceholder以及surface客户端(本例子中指的是camera)的关系,surface及其client(客 ...

  3. android surfaceView 黑屏

    最近在做一个viewpager + fragment 切换的页面, 其中一个fragment 打开摄像头,需要surfaceView,但是当切换到这个fragment的前一个个时,这个fragment ...

  4. android下面使用SurfaceView+ mediaPlayer播放视频

    final SurfaceView surfaceView = new SurfaceView(StartupActivity.this); StartupActivity.this.mediaPla ...

  5. Android 之surfaceView (画动态圆圈)

      通过之前介绍的如何自定义View, 我们知道使用它可以做一些简单的动画效果.它通过不断循环的执行View.onDraw方法,每次执行都对内部显示的图形做一些调整,我们假设 onDraw方法每秒执行 ...

  6. Surface与SurfaceView、SurfaceHolder

    什么是Surface? android API的解释是:Handle onto a raw buffer that is being managed by the screen compositor ...

  7. android SurfaceView中播放视频 按视频的原始比例播放

    OnPreparedListener mediaPlayerOnPreparedListener = new OnPreparedListener() { @Override public void ...

  8. Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系

    转载请包含网址:http://blog.csdn.net/pathuang68/article/details/7351317 一.Surface Surface就是“表面”的意思.在SDK的文档中, ...

  9. [安卓] 12、开源一个基于SurfaceView的飞行射击类小游戏

    前言  这款安卓小游戏是基于SurfaceView的飞行射击类游戏,采用Java来写,没有采用游戏引擎,注释详细,条理比较清晰,适合初学者了解游戏状态转化自动机和一些继承与封装的技巧. 效果展示    ...

  10. Android强制设定横屏时,SurfaceView一直黑屏

    接着上一个问题,解决了SurfaceView闪屏问题之后(http://www.cnblogs.com/Joanna-Yan/p/4829325.html),又有了一个新的问题.现在我想设置含有fra ...

随机推荐

  1. C实战:项目构建Make,Automake,CMake

    C实战:项目构建Make,Automake,CMake 在本系列文章<C实战:强大的程序调试工具GDB>中我们简要学习了流行的调试工具GDB的使用方法.本文继续"C实战" ...

  2. Dynamics CRM2016 Web API获取实体元数据Picklist属性的Text&Value

    通过组织服务中获取实体picklist字段的text和value可以通过RetrieveAttributeRequest实现,但在使用web api的今天该怎么实现,本文即来一探究竟,本篇基于SDK中 ...

  3. Swift中String和NSString的一个不同之处

    我们知道在Swift中String和NSString是可以互相转换使用的-额-应该是在绝大数情况下可以互相转换使用.在某些情况下可能还有一丝丝略微的差别:比如在涉及到处理字符串中字符索引的时候. 我们 ...

  4. 剑指Offer——知识点储备-故障检测、性能调优与Java类加载机制

    剑指Offer--知识点储备-故障检测.性能调优与Java类加载机制 故障检测.性能调优 用什么工具可以查出内存泄露 (1)MerroyAnalyzer:一个功能丰富的java堆转储文件分析工具,可以 ...

  5. MongoDb 用 mapreduce 统计留存率

    MongoDb 用 mapreduce 统计留存率(金庆的专栏)留存的定义采用的是新增账号第X日:某日新增的账号中,在新增日后第X日有登录行为记为留存 输出如下:(类同友盟的留存率显示)留存用户注册时 ...

  6. 详解EBS接口开发之采购订单导入

    采购订单常用标准表简介 1.1   常用标准表 如下表中列出了与采购订单导入相关的表和说明: 表名 说明 其他信息 po.po_headers_all 采购订单头 采购订单号,采购类型,供应商,地点, ...

  7. UNIX网络编程——进程间通信概述

    一.顺序程序与并发程序特征 顺序程序特征 顺序性封闭性:(运行环境的封闭性)确定性可再现性 并发程序特征 共享性并发性随机性 二.进程互斥 1.由于各进程要求共享资源,而且有些资源需要互斥使用,因此各 ...

  8. iOS让软键盘消失的简单方法

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 一些文本输入控件等待输入时会弹出软键盘,我们可以设置这些控件的 ...

  9. java中hashCode()与equals()详解

    首先之所以会将hashCode()与equals()放到一起是因为它们具备一个相同的作用:用来比较某个东西.其中hashCode()主要是用在hash表中提高 查找效率,而equals()则相对而言使 ...

  10. UNIX网络编程——常用服务器模型总结

    下面有9种服务器模型分别是: 迭代服务器. 并发服务器,为每个客户fork一个进程. 预先派生子进程,每个子进程都调用accept,accept无上锁保护. 预先派生子进程,以文件锁的方式保护acce ...