Android SurfaceView 使用双缓冲机制_双缓冲优化之只改变动态精灵_ Handler线程外通信_弹出对话框与提示信息

SurfaceView是游戏中最常用的组件,但是SurfaceView的动态绘制会造成闪屏、黑屏的现象,利用双缓冲可以缓解这一现象,并且这里对双缓冲就行了二次优化处理,并且Handler与其他线程的通信方式

1、普通双缓冲机制的实现
这里仅截取实现的一部分

// 游戏界面
public class GameView extends SurfaceView implements SurfaceHolder.Callback,Runnable{private Canvas canvas; //画布private Paint paint; //画笔private SurfaceHolder surfaceHolder;//  控制容器public SurfaceHolder getSurfaceHolder() {return surfaceHolder;}public boolean gameRunFlag;  // 子线程标志位private Bitmap bitmapbuffer;// '假屏幕'的'截图',缓冲下屏幕 用来画在假屏幕上,利用双缓冲,减少绘制的时候屏幕闪烁现象private Canvas canvasbuffer;//假的屏幕(画布) ,利用双缓冲,减少绘制的时候屏幕闪烁现象private Context context;    // 绘制到的目标容器private static GameView gameView; //动画绘制'管家',总管所有的屏幕绘制动画,可通过管家向页面提交控制的事件及结果//与其他线程通信private Handler handler = new Handler();//将背景的静止元素只绘画一次,下次直接拿去用即可private Canvas canvasback;private Bitmap bitmapback;//覆盖默认构造方法,在指定容器运行public GameView(Context context) {super(context);this.context=context;paint=new Paint();surfaceHolder=getHolder();gameRunFlag=true;gameView=this;/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **                      屏幕缓冲                                   ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *///假屏幕的图片(类似屏幕截图了),缓冲下屏幕,用来画在假屏幕上bitmapbuffer= Bitmap.createBitmap(Config.deviceWidth,Config.deviceHeight,Bitmap.Config.ARGB_8888);//假的屏幕(就是在一个画布上画了假屏幕的图片),并且把假屏幕的内容缓冲到 假屏幕图片上canvasbuffer=new Canvas(bitmapbuffer);/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **                      游戏背景                                   ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */bitmapback= Bitmap.createBitmap(Config.deviceWidth,Config.deviceHeight,Bitmap.Config.ARGB_8888);canvasback=new Canvas(bitmapback);//surfaceview 进行而外的操作用的线程handler= new Handler();//getHolder().addCallback(this);surfaceHolder.addCallback(this);//surfaceCreated(surfaceHolder);//Log.i("游戏界面","标志位="+gameRunFlag);}

双缓冲实现及优化
在普通的双缓冲中我们是将屏幕全部重新绘制一遍的,但是其实我们改变的只是一部分,而对于一些相对来说静止的如背景动画、工具栏等其实是不会改变的,我们可以把这一部分剥离出来,只绘制一次,这样就减少了绘制量,提高绘制的效率,实现如下:

//线程@Overridepublic void run() {//Log.i("游戏界面","run="+gameRunFlag);/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **                      游戏背景  只画一次静止的背景元素               ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *///画背景canvasback.drawBitmap(Config.gameImg_back,0,0,paint);//画工具栏canvasback.drawBitmap(Config.border_back,0,(Config.deviceHeight-(Config.deviceHeight/7)),paint);//画杀敌图标canvasback.drawBitmap(Config.bate_logo,Config.deviceWidth-(Config.deviceWidth-Config.NenegLiang_Context_X)*2+Config.deviceWidth/192, (float) (Config.deviceHeight/8*6.9),paint);//画退出按钮canvasback.drawBitmap(Config.gema_over,Config.game_over_X ,Config.game_over_Y,paint);/*动态元素绘制*/while(gameRunFlag){synchronized (surfaceHolder){//线程同步锁try{//锁住画布canvas=surfaceHolder.lockCanvas();/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **                     屏幕缓冲,把内容先缓冲到假屏幕里                 ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *///清空屏幕  画背景canvasbuffer.drawBitmap(bitmapback,0,0,null);//画能量图标 和 能量值paint.setColor(Color.rgb(0 ,255 ,255));paint.setTextSize(Config.deviceHeight/18);canvasbuffer.drawText("+"+Config.L_number,Config.NenegLiang_Context_X+Config.neng_logo[0].getWidth(),Config.NenegLiang_Context_Y+Config.deviceHeight/108,paint);canvasbuffer.drawBitmap(Config.neng_logo[this.neng_index],Config.NenegLiang_Context_X-Config.deviceWidth/192,(float) (Config.deviceHeight/8*6.9),paint);if(System.currentTimeMillis()-this.neng_time>400){this.neng_index=(this.neng_index+1)%Config.neng_logo.length;this.neng_time=System.currentTimeMillis();}//画杀敌图标 和 击杀数paint.setColor(Color.rgb(255 ,0 ,0));canvasbuffer.drawText("+"+Config.SCORE,Config.deviceWidth-(Config.deviceWidth-Config.NenegLiang_Context_X)*2+Config.bate_logo.getWidth()+Config.deviceWidth/192,Config.NenegLiang_Context_Y+Config.deviceHeight/108,paint);//画笔还原paint.setColor(color);updateData();//调用更新数据ondraw(canvasbuffer);//更新数据后,再绘制容器的全部内容
//                    canvasbuffer.setBitmap(bitmapbuffer);/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **                      把缓冲的假屏幕,画到真正的屏幕里面                                 **                          (就行照镜子一样的照上去)                                   ** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */canvas.drawBitmap(bitmapbuffer,0,0,null);}catch(Exception e){e.getMessage();}finally{//开锁,画布可以被再次更新了if(canvas!=null) {surfaceHolder.unlockCanvasAndPost(canvas);}}
//                gameRunFlag=false;}//锁外休眠 给其他线程留运行空间try {Thread.sleep(50);} catch (InterruptedException e) {e.printStackTrace();}}}

2、Handler线程外通信
SurfaceView中是一个自线程,依赖于另外的实现线程来启动,如果我们需要在屏幕上显示提示信息,绘制弹出对话框等,那么就需要使用Handler来实现与外部的通信,实现如下:
这里仅截取一部分代码

//游戏结束 对话框public void gameOver(){handler.post(new Runnable() {@Overridepublic void run() {try{Thread.sleep(50);//调用弹出对话框的依赖界面自生管理者RunYXActivity.getRunActivity().gameOver();
//                    System.exit(0);//surfaceDestroyed(surfaceHolder);}catch(Exception e){e.printStackTrace();}}});}
//显示提示信息handler.post(new Runnable(){@Overridepublic void run() {Toast.makeText(context,name+"被杀!",Toast.LENGTH_LONG).show();}});

其实我们很容易发现Handler也是启动来一个子线程来实现的通信


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部