论坛首页 移动开发技术论坛

Android中SurfaceView的使用示例

浏览 75042 次
精华帖 (8) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-07-05  

SurfaceView在游戏开发中有着举足轻重的地位,它对于画面的控制有着更大的自由度(不像View要用handler来更新,关于View的),但这方面的参考资料并不是太多,能找到的例子都有点喧宾夺主的感觉,不能把使用的流程清晰展示出来,下面是个简单的示例,力求把流程清楚展示,其他的可简则简。

 

程序效果:用线程画一个蓝色的长方形。

package com.ray.test;
/*
 * SurfaceView的示例程序
 * 演示其流程
 */
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class Test extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
    }
    
    //内部类
    class MyView extends SurfaceView implements SurfaceHolder.Callback{

    	SurfaceHolder holder;
		public MyView(Context context) {
			super(context);
			holder = this.getHolder();//获取holder
			holder.addCallback(this);
			//setFocusable(true);
			
		}

		@Override
		public void surfaceChanged(SurfaceHolder holder, int format, int width,
				int height) {
			
		}

		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			new Thread(new MyThread()).start();
		}

		@Override
		public void surfaceDestroyed(SurfaceHolder holder) {
			
		}
		
		//内部类的内部类
		class MyThread implements Runnable{

			@Override
			public void run() {
				Canvas canvas = holder.lockCanvas(null);//获取画布
				Paint mPaint = new Paint();
				mPaint.setColor(Color.BLUE);
				
				canvas.drawRect(new RectF(40,60,80,80), mPaint);
				holder.unlockCanvasAndPost(canvas);//解锁画布,提交画好的图像
				
			}
			
		}
    	
    }
}

 

   发表时间:2009-09-18  
在用SurfaceView时遇到问题请指点.
每次把画当前正方形时,把上次的清除掉,现在显示很乱画图代码如下
  
	public void selectSmallPicture(Point _origialPoint)
	{
		
		if(_origialPoint == null)
		{
			return ;
		}
		
		Canvas canvas = holder.lockCanvas();// 获取画布
		
		int startX =  _origialPoint.x * (PICTURE_EXTENT + CUBICLE) - 1;
		int startY =  _origialPoint.y * (PICTURE_EXTENT + CUBICLE) - 1;
		//canvas.save();
		
		Paint linePaint = new Paint();
		linePaint.setColor(Color.RED);
		canvas.drawLine(startX, startY,  startX , startY + PICTURE_EXTENT, linePaint);
		canvas.drawLine(startX, startY,  startX + PICTURE_EXTENT, startY , linePaint);
		canvas.drawLine(startX+ PICTURE_EXTENT, startY,  startX + PICTURE_EXTENT, startY + PICTURE_EXTENT, linePaint);
		canvas.drawLine(startX, startY + PICTURE_EXTENT,  startX + PICTURE_EXTENT, startY + PICTURE_EXTENT, linePaint);
		
		if(tempPoint!=null)
		{
			startX =  tempPoint.x * (PICTURE_EXTENT + CUBICLE) - 1;
			startY =  tempPoint.y * (PICTURE_EXTENT + CUBICLE) - 1;
			linePaint.setColor(bgcolor);
			canvas.drawLine(startX, startY,  startX , startY + PICTURE_EXTENT, linePaint);
			canvas.drawLine(startX, startY,  startX + PICTURE_EXTENT, startY , linePaint);
			canvas.drawLine(startX+ PICTURE_EXTENT, startY,  startX + PICTURE_EXTENT, startY + PICTURE_EXTENT, linePaint);
			canvas.drawLine(startX, startY + PICTURE_EXTENT,  startX + PICTURE_EXTENT, startY + PICTURE_EXTENT, linePaint);
		}
		

		canvas.restore();
		holder.unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像
		tempPoint  = _origialPoint;
	}




0 请登录后投票
   发表时间:2009-09-18   最后修改:2009-09-18
ansili 写道
在用SurfaceView时遇到问题请指点.
每次把画当前正方形时,把上次的清除掉,现在显示很乱画图代码如下
  
	public void selectSmallPicture(Point _origialPoint)
	{
		
		if(_origialPoint == null)
		{
			return ;
		}
		
		Canvas canvas = holder.lockCanvas();// 获取画布
		
		int startX =  _origialPoint.x * (PICTURE_EXTENT + CUBICLE) - 1;
		int startY =  _origialPoint.y * (PICTURE_EXTENT + CUBICLE) - 1;
		//canvas.save();
		
		Paint linePaint = new Paint();
		linePaint.setColor(Color.RED);
		canvas.drawLine(startX, startY,  startX , startY + PICTURE_EXTENT, linePaint);
		canvas.drawLine(startX, startY,  startX + PICTURE_EXTENT, startY , linePaint);
		canvas.drawLine(startX+ PICTURE_EXTENT, startY,  startX + PICTURE_EXTENT, startY + PICTURE_EXTENT, linePaint);
		canvas.drawLine(startX, startY + PICTURE_EXTENT,  startX + PICTURE_EXTENT, startY + PICTURE_EXTENT, linePaint);
		
		if(tempPoint!=null)
		{
			startX =  tempPoint.x * (PICTURE_EXTENT + CUBICLE) - 1;
			startY =  tempPoint.y * (PICTURE_EXTENT + CUBICLE) - 1;
			linePaint.setColor(bgcolor);
			canvas.drawLine(startX, startY,  startX , startY + PICTURE_EXTENT, linePaint);
			canvas.drawLine(startX, startY,  startX + PICTURE_EXTENT, startY , linePaint);
			canvas.drawLine(startX+ PICTURE_EXTENT, startY,  startX + PICTURE_EXTENT, startY + PICTURE_EXTENT, linePaint);
			canvas.drawLine(startX, startY + PICTURE_EXTENT,  startX + PICTURE_EXTENT, startY + PICTURE_EXTENT, linePaint);
		}
		

		canvas.restore();
		holder.unlockCanvasAndPost(canvas);// 解锁画布,提交画好的图像
		tempPoint  = _origialPoint;
	}





Android surfaceview 的画图机制是这样设计的,只能画一次背景,再画你想画的才可以!
0 请登录后投票
   发表时间:2009-09-18  
那如果我想在上次画的基础上接着画呢?。
  也就是说我第一次在surfaceview 画了一个方块,再次接到用户的动作时在上次所画结果上接着在surfaceview 再画一个方块.此时surfaceview 上已经存在两个方块了。
   surfaceview  能否胜任? 需要怎么做?
0 请登录后投票
   发表时间:2009-09-18  
ansili 写道
那如果我想在上次画的基础上接着画呢?。
  也就是说我第一次在surfaceview 画了一个方块,再次接到用户的动作时在上次所画结果上接着在surfaceview 再画一个方块.此时surfaceview 上已经存在两个方块了。
   surfaceview  能否胜任? 需要怎么做?

如果要保留当前的接着画,SurfaceView是无法做到的!
0 请登录后投票
   发表时间:2009-09-20  
每次画2个方块
0 请登录后投票
   发表时间:2009-09-22  
raymondlueng 写道

SurfaceView在游戏开发中有着举足轻重的地位,它对于画面的控制有着更大的自由度(不像View要用handler来更新,关于View的),但这方面的参考资料并不是太多,能找到的例子都有点喧宾夺主的感觉,不能把使用的流程清晰展示出来,下面是个简单的示例,力求把流程清楚展示,其他的可简则简。

 

程序效果:用线程画一个蓝色的长方形。

package com.ray.test;
/*
 * SurfaceView的示例程序
 * 演示其流程
 */
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class Test extends Activity {
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new MyView(this));
    }
    
    //内部类
    class MyView extends SurfaceView implements SurfaceHolder.Callback{

    	SurfaceHolder holder;
		public MyView(Context context) {
			super(context);
			holder = this.getHolder();//获取holder
			holder.addCallback(this);
			//setFocusable(true);
			
		}

		@Override
		public void surfaceChanged(SurfaceHolder holder, int format, int width,
				int height) {
			
		}

		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			new Thread(new MyThread()).start();
		}

		@Override
		public void surfaceDestroyed(SurfaceHolder holder) {
			
		}
		
		//内部类的内部类
		class MyThread implements Runnable{

			@Override
			public void run() {
				Canvas canvas = holder.lockCanvas(null);//获取画布
				Paint mPaint = new Paint();
				mPaint.setColor(Color.BLUE);
				
				canvas.drawRect(new RectF(40,60,80,80), mPaint);
				holder.unlockCanvasAndPost(canvas);//解锁画布,提交画好的图像
				
			}
			
		}
    	
    }
}

 

根据楼主的demo我也写了个小小的demo,可就是物体移动的时候比较慢,不知道是为什么?

package com.mcgk.paopao;

import android.app.Activity;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.mcgk.paopao.Paopao.MyView.MyThread;
import com.mcgk.util.BackgroundUtil;

public class Paopao extends Activity {
	private MyThread mythread;
	private static boolean drawFlag = false;
	private static int x = 14;
	private static int y = 20;
	
	/** 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 {

		SurfaceHolder holder;

		public MyView(Context context) {
			super(context);
			holder = this.getHolder();// 获取holder
			holder.addCallback(this);
			setFocusable(true);

		}
		
		@Override
		protected void onDraw(Canvas canvas) {
			// TODO Auto-generated method stub
			super.onDraw(canvas);
			Resources r = this.getContext().getResources();
			BackgroundUtil.drawBackground(r, canvas);
			BackgroundUtil.drawTree(r, canvas, x, y);
			drawFlag = true;
		}

		@Override
		public boolean onKeyDown(int keyCode, KeyEvent event) {
			// TODO Auto-generated method stub
			return mythread.onKeyDown(keyCode, event);
		}

		@Override
		public boolean onKeyUp(int keyCode, KeyEvent event) {
			// TODO Auto-generated method stub
			return mythread.onKeyUp(keyCode, event);
		}

		@Override
		public void surfaceChanged(SurfaceHolder holder, int format, int width,
				int height) {

		}

		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			mythread = new MyThread(holder, this);
			new Thread(mythread).start();
		}

		@Override
		public void surfaceDestroyed(SurfaceHolder holder) {

		}
		
		class MyThread implements Runnable {
			private SurfaceHolder holder;
			private MyView _panel;  
			public MyThread(SurfaceHolder holder, MyView panel) {
				this.holder = holder;
				this._panel = panel;
			}

			public boolean onKeyUp(int keyCode, KeyEvent event) {
				// TODO Auto-generated method stub
				return false;
			}

			public boolean onKeyDown(int keyCode, KeyEvent event) {
				// TODO Auto-generated method stub
				synchronized (holder) {
					if (keyCode == KeyEvent.KEYCODE_DPAD_UP){
						y = y - 30;
					}else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN){
						y = y + 30;
					}else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT){
						x = x - 30;
					}else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT){
						x = x + 30;
					}
				}
				drawFlag = false;
				return false;
			}

			@Override
			public void run() {
				Canvas c;
				while (true) {
					c = null;
					if(drawFlag){
						try {
							Thread.sleep(1);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						continue;
					}
					try {
						c = holder.lockCanvas(null);
						synchronized (holder) {
							_panel.onDraw(c);
						}
					} finally {
						if (c != null) {
							holder.unlockCanvasAndPost(c);
						}
					}
				}  
			}

		}

	}
}
 
0 请登录后投票
   发表时间:2009-10-11  
我明白了,更新画面时不用sleep,看LunarLander的例子里更新UI的线程也是一直狂跑的,占满了一个CPU
0 请登录后投票
   发表时间:2009-10-11   最后修改:2009-10-11
brumby007 写道
我明白了,更新画面时不用sleep,看LunarLander的例子里更新UI的线程也是一直狂跑的,占满了一个CPU


你错了,如果你不sleep而狂刷,你会发现不仅你的短信、电话等后台程序工作缓慢,而且你还能看到如下的警告信息

引用
10-11 13:20:01.534: WARN/SurfaceComposerClient(1938): lock_layer timed out (is the CPU pegged?) layer=1, lcblk=0x424d00a0, state=00000011 (was 00000012)
10-11 13:20:01.534: WARN/SurfaceFlinger(99): executeScheduledBroadcasts() skipped, contention on the client. We'll try again later...
10-11 13:20:01.534: WARN/SurfaceComposerClient(1938): lock_layer() timed out but didn't appear to need to be locked and we recovered (layer=1, lcblk=0x424d00a0, state=00000001)


所以,在lock之外sleep是非常必要滴
0 请登录后投票
   发表时间:2009-10-11  
谢谢楼上大哥的回复,可是不知道为什么在lunarlander里面是这样实现的,也没有做sleep,我看logcat打出来的东西是一直在狂刷的:
        public void run() {
            while (mRun) {
                Canvas c = null;
                try {
                    c = mSurfaceHolder.lockCanvas(null);
                    synchronized (mSurfaceHolder) {
                        if (mMode == STATE_RUNNING) updatePhysics();
                        Log.d("test", ">>>>>>>>>>>>dodraw");
                        doDraw(c);
                    }
                } finally {
                    // do this in a finally so that if an exception is thrown
                    // during the above, we don't leave the Surface in an
                    // inconsistent state
                    if (c != null) {
                        mSurfaceHolder.unlockCanvasAndPost(c);
                    }
                }
            }
        }

而且如果我用sleep的话,物体移动会有明显卡住的感觉。不知道是怎么回事?
小弟初学,还请赐教
0 请登录后投票
论坛首页 移动开发技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics