Android开发之SurfaceView

简介:

如果做游戏或者视频相关开发的时候,将会用到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);
// 结束锁定画图,并提交改变。

测试代码如下:

package com.blueeagle;

import android.app.Activity;
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.view.SurfaceHolder;
 import android.view.SurfaceView;
 
public class SurfaceView01 extends Activity {
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(new MyView(this));
     }
     //视图内部类
     class MyView extends SurfaceView implements SurfaceHolder.Callback
     {
         private SurfaceHolder holder;
         private MyThread myThread; 
         public MyView(Context context) {
             super(context);
             // TODO Auto-generated constructor stub
             holder = this.getHolder();
             holder.addCallback(this);
             myThread = new MyThread(holder);//创建一个绘图线程
         }
 
         @Override
         public void surfaceChanged(SurfaceHolder holder, int format, int width,
                 int height) {
             // TODO Auto-generated method stub
             
         }
 
         @Override
         public void surfaceCreated(SurfaceHolder holder) {
             // TODO Auto-generated method stub
             myThread.isRun = true;
             myThread.start();
         }
 
         @Override
         public void surfaceDestroyed(SurfaceHolder holder) {
             // TODO Auto-generated method stub
             myThread.isRun = false;
         }
         
     }
     //线程内部类
     class MyThread extends Thread
     {
         private SurfaceHolder holder;
         public boolean isRun ;
         public  MyThread(SurfaceHolder holder)
         {
             this.holder =holder; 
             isRun = true;
         }
         @Override
         public void run()
         {
             int count = 0;
             while(isRun)
             {
                 Canvas c = null;
                 try
                 {
                     synchronized (holder)
                     {
                         c = holder.lockCanvas();//锁定画布,一般在锁定后就可以通过其返回的画布对象Canvas,在其上面画图等操作了。
                         c.drawColor(Color.BLACK);//设置画布背景颜色
                         Paint p = new Paint(); //创建画笔
                         p.setColor(Color.WHITE);
                         Rect r = new Rect(100, 50, 300, 250);
                         c.drawRect(r, p);
                         c.drawText("这是第"+(count++)+"秒", 100, 310, p);
                         Thread.sleep(1000);//睡眠时间为1秒
                     }
                 }
                 catch (Exception e) {
                     // TODO: handle exception
                     e.printStackTrace();
                 }
                 finally
                 {
                     if(c!= null)
                     {
                         holder.unlockCanvasAndPost(c);//结束锁定画图,并提交改变。
 
                     }
                 }
            }
         }
     }
}

转自:http://blog.csdn.net/redoffice/article/details/6722067/
目录
相关文章
|
4天前
|
安全 Java Android开发
安卓开发中的新趋势:Kotlin与Jetpack的完美结合
【6月更文挑战第20天】在不断进化的移动应用开发领域,Android平台以其开放性和灵活性赢得了全球开发者的青睐。然而,随着技术的迭代,传统Java语言在Android开发中逐渐显露出局限性。Kotlin,一种现代的静态类型编程语言,以其简洁、安全和高效的特性成为了Android开发中的新宠。同时,Jetpack作为一套支持库、工具和指南,旨在帮助开发者更快地打造优秀的Android应用。本文将探讨Kotlin与Jetpack如何共同推动Android开发进入一个新的时代,以及这对开发者意味着什么。
|
1天前
|
XML Java 开发工具
Android Studio开发Android TV
【6月更文挑战第19天】
|
5天前
|
存储 Java 数据库连接
Android Java开发异步
【6月更文挑战第15天】
|
3天前
|
Java 开发工具 Android开发
安卓与iOS开发差异解析
【6月更文挑战第21天】本文旨在深入探讨安卓和iOS两大移动操作系统在应用开发过程中的主要差异。通过对比分析,揭示各自的设计哲学、编程语言选择、用户界面构建、性能优化策略以及发布流程的异同。文章将提供开发者视角下的实用信息,帮助他们更好地理解各自平台的特点和挑战,从而做出更明智的开发决策。
|
4天前
|
Java 开发工具 Android开发
探索安卓与iOS开发的核心差异
【6月更文挑战第20天】在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文将深入探讨这两大操作系统在开发过程中的主要区别,包括编程语言、开发工具、用户界面设计哲学、系统架构以及市场分布等方面。通过对这些关键差异的分析,旨在为开发者提供一份实用的指南,帮助他们在面对项目决策时,能够更加明智地选择合适的平台,并针对特定平台优化他们的应用。
|
4天前
|
开发工具 Android开发 iOS开发
探索安卓与iOS开发的差异:从工具到用户体验
【6月更文挑战第20天】在移动应用开发的广阔天地中,安卓和iOS两大平台各自占据半壁江山。本文将深入探讨这两个操作系统在开发环境、编程语言、用户界面设计以及性能优化等方面的关键差异。我们将通过比较分析,揭示各自平台的独特优势和面临的挑战,为开发者提供决策参考,并为最终用户提供更深层次的用户体验洞察。
|
6天前
|
Java Android开发 Swift
探索Android与iOS开发的差异:平台选择对项目成功的影响
【6月更文挑战第18天】在移动应用开发的广阔天地中,Android和iOS两大平台各据一方,它们在市场份额、用户群体及开发环境上各有千秋。本文将深入分析这两个操作系统的开发差异,探讨如何根据项目需求选择合适的平台,并讨论跨平台解决方案的可行性与挑战。我们将通过实际案例,揭示平台选择对项目成功的关键性影响,为开发者提供决策支持。
|
7天前
|
安全 IDE Android开发
探索Android与iOS开发的差异:平台特性与编程实践
【6月更文挑战第17天】在移动应用开发的广阔天地中,Android和iOS两大平台各自占据半壁江山。它们在用户群体、系统架构以及开发环境上的差异,为开发者带来了不同的挑战和机遇。本文深入探讨了这两个平台在技术实现、界面设计、性能优化等方面的主要区别,并提供了实用的开发建议,旨在帮助开发者更好地理解各自平台的特性,从而创造出更加优秀的移动应用。
|
6天前
|
Dart IDE Linux
开发Android应用程序
开发Android应用程序
11 1
|
7天前
|
安全 JavaScript 前端开发
kotlin开发安卓app,JetPack Compose框架,给webview新增一个按钮,点击刷新网页
在Kotlin中开发Android应用,使用Jetpack Compose框架时,可以通过添加一个按钮到TopAppBar来实现WebView页面的刷新功能。按钮位于右上角,点击后调用`webViewState?.reload()`来刷新网页内容。以下是代码摘要: