1.概念

SurfaceView是View类的子类,可以直接从内存或者DMA等硬件接口取得图像数据,是个非常重要的绘图视图。它的特性是:可以在主线程之外的 线程中向屏幕绘图上。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。在游戏开发中多用到SurfaceView,游戏中的背 景、人物、动画等等尽量在画布canvas中画出。

   SurfaceHolder是一个接口,其作用就像一个关于Surface的监听器。提供访问和控制SurfaceView背后的Surface 相关的方法 (providingaccess and control over this SurfaceView's underlying surface),它通过三个回调方法,让我们可以感知到Surface的创建、销毁或者改变。在SurfaceView中有一个方法getHolder,可以很方便地获得SurfaceView所对应的Surface所对应的SurfaceHolder

  所有SurfaceView和SurfaceHolder.Callback中声明的方法,必须在运行SurfaceView窗口中的线程中调用(典型地,就是应用的主线程。译注:即UI线程),因为它们需要正确地将同时被绘制线程访问的各种状态进行同步

SurfaceView可见就会被创建,不可见就会被销毁

2.实现方法

1)实现步骤

a.继承SurfaceView

b.实现SurfaceHolder.Callback接口

2)需要重写的方法

(1)public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}  //在surface的大小发生改变时激发

(2)public void surfaceCreated(SurfaceHolder holder){}  //在创建时激发,一般在这里调用画图的线程。

(3)public void surfaceDestroyed(SurfaceHolder holder) {}  //销毁时激发,一般在这里将画图的线程停止、释放。

3)SurfaceHolder

  SurfaceHolder,surface的控制器,用来操纵surface。处理它的Canvas上画的效果和动画,控制表面,大小,像素等。
几个需要注意的方法:

(1)、abstract void addCallback(SurfaceHolder.Callback callback);
// 给SurfaceView当前的持有者一个回调对象。
(2)、abstract Canvas lockCanvas();
// 锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
(3)、abstract Canvas lockCanvas(Rect dirty);
// 锁定画布的某个区域进行画图等..因为画完图后,会调用下面的unlockCanvasAndPost来改变显示内容。
// 相对部分内存要求比较高的游戏来说,可以不用重画dirty外的其它区域的像素,可以提高速度。
(4)、abstract void unlockCanvasAndPost(Canvas canvas);
// 结束锁定画图,并提交改变。

4)总结整个过程

  继承SurfaceView并实现SurfaceHolder.Callback接口 ----> SurfaceView.getHolder()获得SurfaceHolder对象 ---->SurfaceHolder.addCallback(callback)添加回调函数 ---->SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布----> Canvas绘画 ---->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。

实例一:
画圆:在xml文件中引用自定义SurfaceVIew就ok了

/**
*按下home键,页面不可见
* Created by Administrator on 2016/10/3.
*/
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback{ private final SurfaceHolder holder;
private Paint paint;
private MyThread thread;
private boolean isDraw = false; public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
holder = this.getHolder();
holder.addCallback(this); //创建画笔
createPaint();
}
private void createPaint() {
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
//设置画的样式为画边框
paint.setStyle(Paint.Style.STROKE);
} /**
*页面可见调用
* @param holder
*/
@Override
public void surfaceCreated(SurfaceHolder holder) {
//创建一个绘图线程
thread = new MyThread();
isDraw = true;
thread.start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
} /**
* surfaceView页面不可见调用
* @param holder
*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//该方法在主线程中运行
isDraw = false;
Log.i("tag", "surfaceDestroyed: ");
//join方法,阻塞线程,只有当当前线程执行完,才会执行其他线程的方法
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
class MyThread extends Thread{
private int radius = 10; @Override
public void run() {
while(isDraw){
Log.i("tag", "run: "+Thread.currentThread().getName());
//同步,避免不同线程在同一个画布上进行绘画操作
synchronized (holder){ //锁定画布
Canvas canvas = holder.lockCanvas();
//第一次进入和退出程序时,canvas为空
if(canvas != null) {
//画圆
canvas.drawCircle(100, 100, radius, paint);
radius += 10;
if (radius > 70) {
radius += 3;
}
// 睡眠,时间不能太长,否则和join方法会产生冲突
SystemClock.sleep(50);
//解锁画布,并提交
holder.unlockCanvasAndPost(canvas);
}
}
}
}
}
}

join和sleep的区别:

Thread.Join()
阻塞调用线程,直至某个线程终止。在此期间,被阻塞线程继续执行标准的COM和SendMessage消息泵。该方法使线程状态包含ThreadState.SleepWaitJoin.
 
该方法可以用来确认某个线程是否结束。如果线程已经结束,则该方法立即返回,否则阻塞直至线程结束。在某些需要等待其他线程执行结束后,继续后续操作时,可以使用该方法。
该方法有2个带参的重载方法,可以指定阻塞的时间。超时或者线程结束时,该方法将返回。
 
Thread.Sleep(int milliSec)
在指定的时间段内挂起当前线程。此期间不执行的COM和SendMessage消息泵,也不会被系统调度并执行。该方法使线程状态包含ThreadState.SleepWaitJoin.

实例二:

调用摄像头进行拍照:

需要权限:

<uses-permission android:name="android.permission.CAMERA"></uses-permission>
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback {

    private SurfaceView surfaceView;
private ImageView image;
private SurfaceHolder holder;
private Camera camera;
private boolean isDraw = false; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView = (SurfaceView) findViewById(R.id.surfaceView);
image = (ImageView) findViewById(R.id.image);
holder = surfaceView.getHolder();
holder.addCallback(this);
//打开照相机
camera = Camera.open(0);
}
public void onTakePhotos(View view){
/*参数1: 回调
*参数2: 原图片回调
* 参数3: jpg格式图片回调
* */
camera.takePicture(null, null, new Camera.PictureCallback() {
/*data就是图片的字节形式的数据*/
@Override
public void onPictureTaken(byte[] data, Camera camera) {
surfaceView.setVisibility(View.GONE);
image.setVisibility(View.VISIBLE);
image.setImageBitmap(BitmapFactory.decodeByteArray(data,0,data.length));
}
});
}
/*当surfaceView可见的时候调用*/
@Override
public void surfaceCreated(SurfaceHolder holder) { try {
//设置预览参数,与 surfaceView绑定
camera.setPreviewDisplay(holder);
//设置显示的布局为垂直
camera.setDisplayOrientation(90);
//开启预览
camera.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
/*当surfaceView不可见的时候调用*/
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if(camera != null) {
// camera.release();
camera.stopPreview();
}
}
}

效果图:

播放gif图片:在main--new dir--asserts文件夹,将图片放入

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback{

    private SurfaceView surfaceView;
private Movie movie;
private SurfaceHolder surfaceHolder;
private boolean flag;
private MyThread myThread; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView = (SurfaceView) findViewById(R.id.surfaceView); //获得surfaceView的holder对象
surfaceHolder = surfaceView.getHolder();
surfaceHolder.addCallback(this);
try {
//将gif图片拆分成一帧一帧的资源
movie = Movie.decodeStream(getResources().getAssets().open("new.gif")); } catch (IOException e) {
e.printStackTrace();
} } @Override
public void surfaceCreated(SurfaceHolder holder) {
flag = true;
// 开启线程播放gif图片
myThread = new MyThread();
myThread.start(); } @Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override
public void surfaceDestroyed(SurfaceHolder holder) {
//销毁该线程
flag = false;
try {
myThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
} }
class MyThread extends Thread{
@Override
public void run() {
super.run();
long startTime = System.currentTimeMillis();
while(flag){
synchronized (surfaceHolder){
//锁定画板
Canvas canvas = surfaceHolder.lockCanvas();
            if(canvas != null){
   //gif的播放的总时间
   int duration = movie.duration();
              Paint paint = new Paint();
   //得到当前时间
   long currentTime = System.currentTimeMillis();
   // 计算当前应该播放到的位置 设置该时间点播放的帧
   movie.setTime((int) ((currentTime-startTime)%duration));
   //画
   movie.draw(canvas,200,200,null);
   //解锁画板
   surfaceHolder.unlockCanvasAndPost(canvas);
            }
}
}
}
}
}
效果

转自:

Android之SurfaceView使用总结

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. Ildasm.exe(MSIL 反汇编程序)

    MSIL 反汇编程序是 MSIL 汇编程序 (Ilasm.exe) 的伙伴工具. Ildasm.exe 采用包含 Microsoft 中间语言 (MSIL) 代码的可迁移可执行 (PE) 文件,并创建 ...

  2. Parallel for-each loops in .NET C# z

    An IEnumerable object An Action of T which is used to process each item in the list List<string&g ...

  3. HDU 3001 Travelling 3进制状压dp

    题意:10个点,若干条边,边有花费,每个点最多走两次,求走过所有点,花费最少 分析:因为每个点最多走两次,所以联想到3进制,然后枚举状态,就行了(我也是照着网上大神的代码写的) #include &l ...

  4. BZOJ2038: [2009国家集训队]小Z的袜子(hose) 莫队算法

    要使用莫队算法前提 ,已知[l,r]的答案,要能在logn或者O(1)的时间得到[l+1,r],[l-1,r],[l,r-1],[l,r+1],适用于一类不修改的查询 优美的替代品——分块将n个数分成 ...

  5. Testlink & Redmine组合拳演练

    环境:Ubuntu 14.04LTS 一.部署testlink 查看已安装软件: dpkg -l *apache* (apache2.4.7) dpkg -l *php* (未安装) dpkg -l ...

  6. (二)GameMaker:Studio ——使用等高图生成3D地形

    上一篇,我们讲解了GM中导入模型的方法,这节我们来讲地形. 源文件地址:http://pan.baidu.com/share/link?shareid=685772423&uk=2466343 ...

  7. Anti-Grain Geometry 概述

    AGG是一个轻量.灵活.可靠的图形算法库,AGG各部分之间是松耦合的,也即是说各部分可以单独使用. The primary goal of Anti-Grain Geometry is to brea ...

  8. 浅谈 Python 的 with 语句

    with 语句是在 Python 2.5 版本引入的,从 2.6 版本开始成为缺省的功能.with 语句作为 try/finally 编码范式的一种替代,用于对资源访问进行控制的场合.本章对 with ...

  9. POJ 3254 poj3254 Corn Fields

    题意:给出一个n行m列的草地,1表示肥沃,0表示贫瘠,现在要把一些牛放在肥沃的草地上,但是要求所有牛不能相邻,问你有多少种放法. 思路: DP[i][j]=sum(dp[i-1][k]); i表示当前 ...

  10. uva 11995 I Can Guess the Data Structure stack,queue,priority_queue

    题意:给你n个操做,判断是那种数据结构. #include<iostream> #include<cstdio> #include<cstdlib> #includ ...