view, surfaceView, invalidate, p…

1.view

         由此可见View类属于Android开发绘制中的显示老大,任何与绘制有关系的控件都是它的子类。在这篇文章中我主要讲View 与SurFaceView 使用线程刷新屏幕绘制方面的知识。开发中如何去选择使用View还是SurFaceView。我相信读过我前几篇博客的朋友应该知道我在刷新屏幕的时候使用invalidate()方法来重绘,下面我详细的说明一下Andooid刷新屏幕的几种方法。

 

 

          第一种: 在onDraw方法最后调用invalidate()方法,它会通知UI线程重绘 这样 View会重新调用onDraw方法,实现刷新屏幕。 这样写看起来代码非常简洁漂亮,但是它也同时存在一个很大的问题,它和游戏主线程是分开的 它违背了单线程模式,这样操作绘制的话是很不安全的,举个例子 比如程序先进在Activity1中 使用invalidate()方法来重绘, 然后我跳到了Activity2这时候Activity1已经finash()掉 可是Activity1中 的invalidate() 的线程还在程序中,Android的虚拟机不可能主动杀死正在运行中的线程所以这样操作是非常危险的。因为它是在UI线程中被动掉用的所以很不安全。

invalidate()  更新整个屏幕区域

invalidate(Rect rect) 更新Rect区域

invalidate(l, t, r, b) 更新指定矩形区域

 
  1. public void onDraw(Canvas canvas){    
  2.         DosomeThing();    
  3.         invalidate();    
  4. }    

第二种:使用postInvalidate();方法来刷新屏幕 ,调用后它会用handler通知UI线程重绘屏幕,我们可以 new  Thread(this).start(); 开启一个游戏的主线程 然后在主线程中通过调用postInvalidate();方法来刷新屏幕。postInvalidate();方法 调用后 系统会帮我们调用onDraw方法 ,它是在我们自己的线程中调用 通过调用它可以通知UI线程刷新屏幕 。由此可见它是主动调用UI线程的。所以建议使用postInvalidate()方法通知UI线程来刷新整个屏幕。

postInvalidate(left, top, right, bottom) 方法 通过UI线程来刷新规定矩形区域。

 
  1. @Override  
  2. public void run()  
  3.     while (mIsRunning)  
  4.     try  
  5.         Thread.sleep(100);  
  6.                    postInvalidate();  
  7.     catch (InterruptedException e)  
  8.         // TODO Auto-generated catch block  
  9.         e.printStackTrace();  
  10.      
  11.      
  12. }  

View中用到的双缓冲技术

        重绘的原理是 程序根据时间来刷新屏幕 如果有一帧图形还没有完全绘制结束 程序就开始刷新屏幕这样就会造成瞬间屏幕闪烁 画面很不美观,所以双缓冲的技术就诞生了。它存在的目的就是解决屏幕闪烁的问题,下面我说说在自定义View中如何实现双缓冲。

首先我们需要创建一张屏幕大小的缓冲图片,我说一下第三个参数 ARGB 分别代表的是 透明度   红色   绿色     蓝色

Bitmap.Config  ARGB_4444              ARGB  分别占四位  
Bitmap.Config  ARGB_8888              ARGB  分别占八位 
Bitmap.Config  RGB_565                没有透明度(A)   R占5位   G 占6位   B占5位    

一般情况下我们使用ARGB_8888 因为它的效果是最好了 当然它也是最占内存的。

  1. mBufferBitmap Bitmap.createBitmap(mScreenWidth,mScreenHeight,Config.ARGB_8888);  


创建一个缓冲的画布,将内容绘制在缓冲区mBufferBitmap中

 
  1. Canvas mCanvas new Canvas();  
  2. mCanvas.setBitmap(mBufferBitmap);  

最后一次性的把缓冲区mBufferBitmap绘制在屏幕上,怎么样 简单吧 呵呵。

 
  1. @Override  
  2. protected void onDraw(Canvas canvas)  
  3.       
  4.       
  5.     DrawMap(mCanvas,mPaint,mBitmap);  
  6.       
  7.     RenderAnimation(mCanvas);  
  8.       
  9.     UpdateAnimation();  
  10.       
  11.       
  12.     if(isBorderCollision)  
  13.     DrawCollision(mCanvas,"与边界发生碰撞");  
  14.      
  15.       
  16.     if(isAcotrCollision)  
  17.     DrawCollision(mCanvas,"与实体层发生碰撞");  
  18.      
  19.     if(isPersonCollision)  
  20.     DrawCollision(mCanvas,"与NPC发生碰撞");  
  21.      
  22.       
  23.       
  24.     canvas.drawBitmap(mBufferBitmap, 0,0mPaint);  
  25.     super.onDraw(canvas);  
  26. }  

         由此可见view属于被动刷新, 因为我们做的任何刷新的操作实际上都是通知UI线程去刷新。所以在做一些只有通过玩家操作以后才会刷新屏幕的游戏 并非自动刷新的游戏 可以使用view来操作。 

2.SurfaceView 

        从API中可以看出SurfaceView属于View的子类 它是专门为制作游戏而产生的,它的功能非常强大,最重要的是它支持OpenGL ES库,2D和3D的效果都可以实现。创建SurfaceView的时候需要实现SurfaceHolder.Callback接口,它可以用来监听SurfaceView的状态,SurfaceView的改变 SurfaceView的创建 SurfaceView 销毁  我们可以在相应的方法中做一些比如初始化的操作 或者 清空的操作等等。

       使用SurfaceView构建游戏框架它的绘制原理是绘制前先锁定画布 然后等都绘制结束以后 在对画布进行解锁 最后在把画布内容显示到屏幕上。     

代码中是如何实现SurfaceView

首先需要实现 Callback 接口 与Runnable接口 

 

 
  1. public class AnimView extends SurfaceView implements Callback,Runnable  

 

 

获取当前mSurfaceHolder 并且把它加到CallBack回调函数中

 

 
  1. SurfaceHolder  mSurfaceHolder getHolder();  
  2. mSurfaceHolder.addCallback(this);  

 

 

        通过callBack接口监听SurfaceView的状态, 在它被创建的时候开启游戏的主线程,结束的时候销毁。这里说一下在View的构造函数中是拿不到view有关的任何信息的,因为它还没有构建好。 所以通过这个监听我们可以在surfaceCreated()中拿到当前view的属性 比如view的宽高 等等,所以callBack接口还是非常有用处的。

 

 

[java]  view plain copy
  1. @Override  
  2. public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,  
  3.     int arg3)  
  4.     // surfaceView的大小发生改变的时候  
  5.       
  6.  
  7.   
  8. @Override  
  9. public void surfaceCreated(SurfaceHolder arg0)  
  10.       
  11.     mIsRunning true 
  12.     mThread new Thread(this);  
  13.     mThread.start();  
  14.  
  15.   
  16. @Override  
  17. public void surfaceDestroyed(SurfaceHolder arg0)  
  18.  // surfaceView销毁的时候  
  19.     mIsRunning false 
  20.  

 

在游戏主线程循环中在绘制开始 先拿到画布canvas 并使用mSurfaceHolder.lockCanvas()锁定画布,等绘制结束以后 使用mSurfaceHolder.unlockCanvasAndPost(mCanvas)解锁画布,  解锁画布以后画布上的内容才会显示到屏幕上。

 

[java]  view plain copy
  1. @Override  
  2. public void run()  
  3.     while (mIsRunning)  
  4.     try  
  5.         Thread.sleep(100);  
  6.     catch (InterruptedException e)  
  7.         // TODO Auto-generated catch block  
  8.         e.printStackTrace();  
  9.      
  10.       
  11.     //在这里加上线程安全锁  
  12.     synchronized (mSurfaceHolder)  
  13.           
  14.         mCanvas =mSurfaceHolder.lockCanvas();    
  15.         Draw();  
  16.           
  17.         mSurfaceHolder.unlockCanvasAndPost(mCanvas);  
  18.      
  19.      
  20.  

 

 

由此可见SurfaceView 属于主动刷新 ,重绘过程完全是在我们自己的线程中完成 , 由于游戏中肯定会执行各种绚丽的动画效果如果使用被动刷新的View就有可能就会阻塞UI线程,所以SurfaceView 更适合做游戏。

 

 

效果图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值