• Android开发之SurfaceView


    转自http://blog.csdn.net/redoffice/article/details/6722067/

    Android开发之SurfaceView

    /*

     *  Android开发之SurfaceView

     *  北京Android俱乐部群:167839253

     *  Created on: 2011-8-26

     *  Author: blueeagle

     *  Email: liujiaxiang@gmail.com

     */

     

           在前面学习视频播放和简单照相机的制作的时候,用到了SurfaceView这个类。那么这个类是干什么的呢?如果不用这个类,用View类行不行呢?这个看起来是不行的。

    如果做游戏或者视频相关开发的时候,将会用到SurfaceView。对于SurfaceView,首先需要了解一下它自己的位置:

    extends View

    java.lang.Object

       ↳

    android.view.View

     

       ↳

    android.view.SurfaceView

    由手册可知:

    SurfaceView是View类的继承类,这个View里内嵌了一个专门用于绘制的Surface,这个可以类似的理解成为一个在View里的Canvas。你可以控制这个Surface的格式和尺寸。Surfaceview类则控制这个Surface在屏幕上的正确位置。

    《Android高级编程》里这样说:

    在一般情况下,应用程序的View都是在相同的GUI线程中绘制的。这个主应用程序线程同时也用来处理所有的用户交互(例如按钮单击或者文本输入)。

    对于一个View的onDraw()方法,不能够满足将其移动到后台线程中去。因为从后台线程修改一个GUI元素会被显式地禁止的。

    当需要快速地更新View的UI,或者当前渲染代码阻塞GUI线程的时间过长的时候,SurfaceView就是解决上述问题的最佳选择。SurfaceView封装了一个Surface对象,而不是Canvas。这一点很重要,因为Surface可以使用后台线程绘制。对于那些资源敏感的操作,或者那些要求快速更新或者高速帧率的地方,例如使用3D图形,创建游戏,或者实时预览摄像头,这一点特别有用。

           1. 何时应该使用SurfaceView

           SurfaceView使用的方式与任何View所派生的类都是完全相同的。可以像其他View那样应用动画,并把它们放到布局中。

           SurfaceView封装的Surface支持所有标准的Canvas方法进行绘图,同时也支持完全的OpenGL ES 库。

           使用OpenGL,你可以在Surface上绘制任何支持2D或者3D对象,与在2D画布上模拟相同的效果相比,这种方法可以依靠硬件加速(可用的时候)来极大地提高性能。

           对于显示动态的3D图像来说,例如,那些使用Google Earth 功能的应用程序,或者那些提供沉浸体验的交互式游戏,Surface特别有用。它还是实时显示摄像头预览的最佳选择。

    2. 创建一个新的SurfaceView控件

    创建一个新的SurfaceView控件需要创建一个新的扩展了SurfaceView的类,并实现SurfaceHolder.Callback。

    SurfaceHolder回调可以在底层的Surface被创建和销毁的时候通知View,并传递给它SurfaceHolder对象的引用,其中包含了当前有效的Surface。

    一个典型的SurfaceView 设计模型包括一个由Thread所派生的类,它可以接收对当前的SurfaceHolder的引用,并独立地更新它。

    3. 使用SurfaceView创建3D控件

    Android完全支持OpenGL ES 3D 渲染框架,其中包含了对设备的硬件加速的支持。SurfaceView控件提供了一个表面,可以在它上面渲染你的OpenGL场景。

    那么我们在使用的时候可以这样使用:

    被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。

    主动更新。比如一个人在一直跑动。这就需要一个单独的thread不停的重绘人的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。

     

    可以直接从内存或硬件设备比如相机等取得图像数据,是个非常重要的绘图容器。

    它的特性是:可以在主线程之外的线程中向屏幕绘图。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。

    如何去使用一个SurfaceView:

    首先继承SurfaceView并实现SurfaceHolder.Callback接口。因为使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始。可以被直接复制到显存从而显示出来,这使得显示速度会非常快,而在Surface 被销毁之前必须结束。所以Callback 中的surfaceCreated 和surfaceDestroyed 就成了绘图处理代码的边界。

    需要重写的方法

     (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) {}

         //销毁时激发,一般在这里将画图的线程停止、释放。

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

    关于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);
    // 结束锁定画图,并提交改变。

    测试代码如下:

    [java] view plaincopy
    1. /* 
    2.  *  Android开发之SurfaceView 
    3.  *  SurfaceView01.java 
    4.  *  Created on: 2011-8-25 
    5.  *  Author: blueeagle 
    6.  *  Email: liujiaxiang@gmail.com 
    7.  */  
    8.   
    9. package com.blueeagle;  
    10.   
    11. import android.app.Activity;  
    12.  import android.content.Context;  
    13.  import android.graphics.Canvas;  
    14.  import android.graphics.Color;  
    15.  import android.graphics.Paint;  
    16.  import android.graphics.Rect;  
    17.  import android.os.Bundle;  
    18.  import android.view.SurfaceHolder;  
    19.  import android.view.SurfaceView;  
    20.    
    21. public class SurfaceView01 extends Activity {  
    22.      /** Called when the activity is first created. */  
    23.      @Override  
    24.      public void onCreate(Bundle savedInstanceState) {  
    25.          super.onCreate(savedInstanceState);  
    26.          setContentView(new MyView(this));  
    27.      }  
    28.      //视图内部类  
    29.      class MyView extends SurfaceView implements SurfaceHolder.Callback  
    30.      {  
    31.          private SurfaceHolder holder;  
    32.          private MyThread myThread;   
    33.          public MyView(Context context) {  
    34.              super(context);  
    35.              // TODO Auto-generated constructor stub  
    36.              holder = this.getHolder();  
    37.              holder.addCallback(this);  
    38.              myThread = new MyThread(holder);//创建一个绘图线程  
    39.          }  
    40.    
    41.          @Override  
    42.          public void surfaceChanged(SurfaceHolder holder, int format, int width,  
    43.                  int height) {  
    44.              // TODO Auto-generated method stub  
    45.                
    46.          }  
    47.    
    48.          @Override  
    49.          public void surfaceCreated(SurfaceHolder holder) {  
    50.              // TODO Auto-generated method stub  
    51.              myThread.isRun = true;  
    52.              myThread.start();  
    53.          }  
    54.    
    55.          @Override  
    56.          public void surfaceDestroyed(SurfaceHolder holder) {  
    57.              // TODO Auto-generated method stub  
    58.              myThread.isRun = false;  
    59.          }  
    60.            
    61.      }  
    62.      //线程内部类  
    63.      class MyThread extends Thread  
    64.      {  
    65.          private SurfaceHolder holder;  
    66.          public boolean isRun ;  
    67.          public  MyThread(SurfaceHolder holder)  
    68.          {  
    69.              this.holder =holder;   
    70.              isRun = true;  
    71.          }  
    72.          @Override  
    73.          public void run()  
    74.          {  
    75.              int count = 0;  
    76.              while(isRun)  
    77.              {  
    78.                  Canvas c = null;  
    79.                  try  
    80.                  {  
    81.                      synchronized (holder)  
    82.                      {  
    83.                          c = holder.lockCanvas();//锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。  
    84.                          c.drawColor(Color.BLACK);//设置画布背景颜色  
    85.                          Paint p = new Paint(); //创建画笔  
    86.                          p.setColor(Color.WHITE);  
    87.                          Rect r = new Rect(10050300250);  
    88.                          c.drawRect(r, p);  
    89.                          c.drawText("这是第"+(count++)+"秒"100310, p);  
    90.                          Thread.sleep(1000);//睡眠时间为1秒  
    91.                      }  
    92.                  }  
    93.                  catch (Exception e) {  
    94.                      // TODO: handle exception  
    95.                      e.printStackTrace();  
    96.                  }  
    97.                  finally  
    98.                  {  
    99.                      if(c!= null)  
    100.                      {  
    101.                          holder.unlockCanvasAndPost(c);//结束锁定画图,并提交改变。  
    102.    
    103.                      }  
    104.                  }  
    105.             }  
    106.          }  
    107.      }  
    108. }  

  • 相关阅读:
    Java 概述
    vue组件事件
    小程序注册
    小程序基础知识梳理
    小程序简介
    公众号
    jeecg-boot
    小程序背景图
    bootstrap-select采坑
    存取cookie
  • 原文地址:https://www.cnblogs.com/walccott/p/4957583.html
Copyright © 2020-2023  润新知