认识 SurfaceView
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的更多相关文章
- SurfaceView 绘制分形图
之前一直做的是应用类,这次抽时间,参考网上资料实践了下SurfaceView.目标是在页面上画一个科赫曲线的分形图. 代码如下: package com.example.fredric.demo02; ...
- Android中surface,surfaceview,sufaceholder以及surface客户端的关系
这里以照相机camera功能的实现来解释surface,surfaceview,sufaceholder以及surface客户端(本例子中指的是camera)的关系,surface及其client(客 ...
- android surfaceView 黑屏
最近在做一个viewpager + fragment 切换的页面, 其中一个fragment 打开摄像头,需要surfaceView,但是当切换到这个fragment的前一个个时,这个fragment ...
- android下面使用SurfaceView+ mediaPlayer播放视频
final SurfaceView surfaceView = new SurfaceView(StartupActivity.this); StartupActivity.this.mediaPla ...
- Android 之surfaceView (画动态圆圈)
通过之前介绍的如何自定义View, 我们知道使用它可以做一些简单的动画效果.它通过不断循环的执行View.onDraw方法,每次执行都对内部显示的图形做一些调整,我们假设 onDraw方法每秒执行 ...
- Surface与SurfaceView、SurfaceHolder
什么是Surface? android API的解释是:Handle onto a raw buffer that is being managed by the screen compositor ...
- android SurfaceView中播放视频 按视频的原始比例播放
OnPreparedListener mediaPlayerOnPreparedListener = new OnPreparedListener() { @Override public void ...
- Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系
转载请包含网址:http://blog.csdn.net/pathuang68/article/details/7351317 一.Surface Surface就是“表面”的意思.在SDK的文档中, ...
- [安卓] 12、开源一个基于SurfaceView的飞行射击类小游戏
前言 这款安卓小游戏是基于SurfaceView的飞行射击类游戏,采用Java来写,没有采用游戏引擎,注释详细,条理比较清晰,适合初学者了解游戏状态转化自动机和一些继承与封装的技巧. 效果展示 ...
- Android强制设定横屏时,SurfaceView一直黑屏
接着上一个问题,解决了SurfaceView闪屏问题之后(http://www.cnblogs.com/Joanna-Yan/p/4829325.html),又有了一个新的问题.现在我想设置含有fra ...
随机推荐
- Docker容器访问控制
容器的访问控制,主要通过 Linux 上的 iptables 防火墙来进行管理和实现.iptables 是 Linux 上默认的防火墙软件,在大部分发行版中都自带. 容器访问外部网络 容器要想访问外部 ...
- 动手试试Android Studio插件开发
由于业务关系,经常需要写一些表单页面,基本也就是简单的增删改查然后上传,做过几个页面之后就有点想偷懒了,这么低水平重复性的体力劳动,能不能用什么办法自动生成呢,查阅相关资料,发现android stu ...
- JBOSS EAP 6 系列六 公共模块的jar配置到jboss的modules详细配置
公司项目中遇到并要解决的问题 1:原则上除了自己写的代码之外,公共的jar不应该都在打包的时候打包到ear里面,这样的话包太大,也不符合的分层的逻辑,在jboss容器内部,每个ear的包重复jar都会 ...
- Android控制软键盘的弹出和隐藏
弹出软键盘 前提:必须要有一个可以编辑的控件(EditText),并且当前已经获取焦点 /** * 弹出软键盘 */ public void openKeyboard(View view) { // ...
- [ExtJS5学习笔记]第二十二节 Extjs5中使用beforeLabelTpl配置给标签增加必填选项星号标志
本文地址:http://blog.csdn.net/sushengmiyan/article/details/39395753 官方例子:http://docs.sencha.com/extjs/5. ...
- ExtJS学习(三)Grid表格
表格说明 Ext中的表格功能非常强大,包括排序.缓存.拖动.隐藏某一列.自动显示行号.列汇总.单元格编辑等实用功能.表格由类Ext.grid.GridPanel定义,继承自Ext.Panel,其xty ...
- 每个程序员都应该用MBP
换笔记本的想法很久了,前段时间换工作就想看换工作之后是什么情况吧.可能工作配的笔记本就是MBP.后来发现是想多了,新工作的笔记本是Thinkpad X240, 配置完全够用了,8G内存+128G的FL ...
- Android开发学习之路--Android Studio项目目录结构简介
既然已经搭建好环境了,那就对Android Studio中项目目录结构做个简单的了解了,这里以最简单的Hello工程为例子,新建好工程后看如下三个工程视图: 1.Android工程 manifests ...
- 从二进制数据流中构造GDAL可以读取的图像数据
在很多时候,我们的图像数据往往都不是文件方式存储在磁盘上,而是可能从网络或者数据库中获取的是二进制的图像数据流.最简单的方式和最容易想到的方式就是将这个文件流保存到磁盘上形成一个文件,然后再使用GDA ...
- Linux技巧:一次删除一百万个文件的最快方法
最初的测评 昨天,我看到一个非常有趣的删除一个目录下的海量文件的方法.这个方法来自http://www.quora.com/How-can-someone-rapidly-delete-400-000 ...