surfaceview变得可见时,surface被创建;surfaceview隐藏前,surface被销毁。这样能节省资源。如果你要查看 surface被创建和销毁的时机,可以重载surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)。
surfaceview的核心在于提供了两个线程:UI线程和渲染线程。这里应注意:
1> 所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。渲染线程所要访问的各种变量应该作同步处理。
2> 由于surface可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()之间有效,所以要确保渲染线程访问的是合法有效的surface。
1、定义
可以直接从内存或者DMA等硬件接口取得图像数据,是个非常重要的绘图容器。
它的特性是:可以在主线程之外的线程中向屏幕绘图上。这样可以避免画图任务繁重的时候造成主线程阻塞,从而提高了程序的反应速度。在游戏开发中多用到SurfaceView,游戏中的背景、人物、动画等等尽量在画布canvas中画出。
2、实现
首先继承SurfaceView并实现SurfaceHolder.Callback接口
使用接口的原因:因为使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始(Surface—表面,这个概念在图形编程中常常被提到。基本上我们可以把它当作显存的一个映射,写入到Surface 的内容
可以被直接复制到显存从而显示出来,这使得显示速度会非常快),而在Surface 被销毁之前必须结束。所以Callback 中的surfaceCreated 和surfaceDestroyed 就成了绘图处理代码的边界。
需要重写的方法
(1)publicvoidsurfaceChanged(SurfaceHolderholder,intformat,intwidth,intheight){}
//在surface的大小发生改变时激发
(2)publicvoidsurfaceCreated(SurfaceHolderholder){}
//在创建时激发,一般在这里调用画图的线程。
(3)publicvoidsurfaceDestroyed(SurfaceHolderholder){}
//销毁时激发,一般在这里将画图的线程停止、释放。
整个过程:继承SurfaceView并实现SurfaceHolder.Callback接口 ----> SurfaceView.getHolder()获得SurfaceHolder对象 ---->SurfaceHolder.addCallback(callback)添加回调函数---->SurfaceHolder.lockCanvas()获得Canvas对象并锁定画布----> Canvas绘画
---->SurfaceHolder.unlockCanvasAndPost(Canvas canvas)结束锁定画图,并提交改变,将图形显示。
下面是SurfaceView的一个简单测试,特别提醒,最好设置SurfaceHolder.addCallBack,重写里面的方法,然后在public void surfaceCreated(SurfaceHolder holder) 里面,在再SurfaceView中画图,防止SurfaceView还没有创建好,而导致的异常。
import java.util.Timer; import java.util.TimerTask; import android.app.Activity; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.os.Bundle; import android.util.Log; import android.view.SurfaceHolder; import android.view.SurfaceView; /** * 画一个布满屏幕的格子 * */ public class SurfaceViewTest2Activity extends Activity { /** Called when the activity is first created. */ private SurfaceView surfaceView; private SurfaceHolder holder; private int screenWidth; private int screenHeight; private Timer timer; private MyTimerTask1 task1; private float currentX = 0.0f;// 记录当前的横向绘制直线的进度 private float currentY = 0.0f;// 记录当前的纵向绘制直线的进度 private Paint paint;// 画笔 private boolean reversion = false;// 控制绘制线条的反转绘制 private int countLine = 0;// 记录画的X是第几条线 @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // 计算屏幕的宽高 screenWidth = getWindowManager().getDefaultDisplay().getWidth(); screenHeight = getWindowManager().getDefaultDisplay().getHeight(); // SurfaceView和holder的初始化 surfaceView = (SurfaceView) findViewById(R.id.sv); holder = surfaceView.getHolder(); holder.addCallback(new SurfaceCallBack()); // 计时器和任务的初始化 timer = new Timer(); task1 = new MyTimerTask1(); // 画笔的设置 paint = new Paint(); paint.setColor(Color.GREEN);// 画笔为绿色... paint.setStrokeWidth(2);// 设置画笔粗细 } public class SurfaceCallBack implements SurfaceHolder.Callback { public void surfaceCreated(SurfaceHolder holder) { timer.schedule(task1, 1000, 5); } public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } public void surfaceDestroyed(SurfaceHolder holder) { } } class MyTimerTask1 extends TimerTask { @Override public void run() { // 开始绘制 drawGrid(currentX, currentY); // 如果不反转的话,那么currentX++,否侧-- if (!reversion) currentX++; else currentX--; // 保持绘制x和y的同步,不过不知道为什么,在模拟器上,X到顶了,而Y没有 // 不过从输出上看,是同步的,可能是模拟器上的问题 currentY = ((float) screenHeight / screenWidth) * currentX; Log.i("test", currentX + " " + currentY); // 如果超过屏幕,那么线条就要反转,并且线条的个数要加1 if (currentX >= screenWidth) { reversion = true; countLine++; } if (currentX <= 0) { reversion = false; countLine++; } } } public void drawGrid(float x, float y) { Canvas canvas = holder.lockCanvas(new Rect(0, 0, screenWidth, screenHeight)); if (!reversion) {//没有反转的绘制情况 canvas.drawLine(0, countLine * 15, x, countLine * 15, paint); canvas.drawLine(countLine * 15, 0, countLine * 15, y, paint); } else {//反转的绘制情况 canvas.drawLine(screenWidth, countLine * 15, x, countLine * 15, paint); canvas.drawLine(countLine * 15, screenHeight, countLine * 15, y, paint); } holder.unlockCanvasAndPost(canvas); } }
参考学习的文章:点击打开链接
参考学习的文章:点击打开链接