Android 双缓冲

Android 双缓冲

  (2010-08-17 11:18:30)
标签: 

android

 

双缓存

 

canvas

 

绘图

 

杂谈

 
SurfaceView本来就是采用双缓冲的技术实现的,所以此处只练习View的双缓冲使用

Java代码 
  1. package com.Aina.Android;  
  2.   
  3. import android.content.Context;  
  4. import android.graphics.Bitmap;  
  5. import android.graphics.Bitmap.Config;  
  6. import android.graphics.Canvas;  
  7. import android.graphics.Paint;  
  8. import android.graphics.drawable.BitmapDrawable;  
  9. import android.view.View;  
  10.   
  11.   
  12. public class GameView extends View  
  13.   
  14.     private Bitmap mBitmap null 
  15.     private Bitmap mBitmap2 null 
  16.     private Canvas mCanvas null 
  17.     private Paint mPaint null 
  18.   
  19.     public GameView(Context context)  
  20.         super(context);  
  21.         mBitmap ((BitmapDrawable) this.getResources().getDrawable(  
  22.                 R.drawable.img)).getBitmap();  
  23.         mBitmap2 Bitmap.createBitmap(320480Config.ARGB_8888);//创建屏幕大小的缓冲区  
  24.         mCanvas new Canvas();  
  25.         mCanvas.setBitmap(mBitmap2);//设置将内容绘制在mBitmap2上面  
  26.         mPaint  new Paint();  
  27.         mCanvas.drawBitmap(mBitmap, 00mPaint);//将图片绘制到缓冲屏幕上面  
  28.      
  29.   
  30.     @Override  
  31.     protected void onDraw(Canvas canvas)  
  32.         super.onDraw(canvas);  
  33.         canvas.drawBitmap(mBitmap2, 00mPaint);  
  34.      
  35.   
  36.  


Java代码 
  1. package com.Aina.Android;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5.   
  6. public class Test_Canvas extends Activity  
  7.       
  8.     private GameView gv null 
  9.     @Override  
  10.     public void onCreate(Bundle savedInstanceState)  
  11.         super.onCreate(savedInstanceState);  
  12.         gv new GameView(this);  
  13.         setContentView(gv);  
  14.      

  15. 注:这里对sufaceview的双缓冲可能理解有误,surfaceview双缓冲应该是有两幅缓存图片,因为如果只有一张缓存图片的话,那么在将缓存图片往屏幕上绘制的时候是不能够往缓存图片上绘制东西的,而如果使用双图片缓存,则可以在往屏幕上绘制缓存图片的同时,往另一张缓存图片中添加东西。
  16. 下面的闪屏问题就是因为双缓冲所致:
  17. Hello Toothy Bunny, 

    On Jan 13, 9:27 am, Toothy Bunny <hongkun...@gmail.com> wrote: 

    > Hi All, 
    > I've been using SurfaceView and Surface for one of my graphics 
    > project. 
    > The problem keep bothering me is that the content in Surface's two 
    > graphic buffers does not synchronized so that when the "lockCanvas- 
    > drawCanvas-unlockCanvas" cycle is running, it shows different content 
    > and generate screen flicker. 

    Here is some information on how the Android graphics system works: 

    In Android, every window is implemented with an underlaying Surface 
    object. A Surface is an object that gets composited onto the 
    framebuffer by SurfaceFlinger, the sytem-wide screen composer. 
    Each Surface is double-buffered, it has a back buffer which is where 
    drawing takes place and a front buffer which is used for composition. 

    When "unlockCanvas()" is called, the back buffer is "posted", which 
    means it's being displayed and  becomes available again. 

    However, the *implementation* of this mechanism is done by swapping 
    the front and back buffers. The back buffer becomes the front buffer 
    and vice-versa. 

    This mechanism ensures that there is a minimal amount of buffer 
    copying (a post operation doesn't move any pixels around) and that 
    there is always a buffer for SurfaceFlinger to use for composition. 
    This last feature is very important because it ensures that the screen 
    never flickers and never shows any artifacts *and* that 
    SurfaceFlinger never has to wait for a Surface to be ready (its front 
    buffer is always ready by definition), this means that a badly written 
    application cannot slowdown or interfere with other application's 
    windows. 

    As a side note, it is worth noting that the main screen itself (the 
    frame buffer) is double-buffered as well and uses the same posting 
    mechanism than any regular surface. 

    It should appear now that because of this posting mechanism, 
    incremental updates are not supported; and this is /the/ key point. 

    Back to your question now: 

    > After doing a bit research, I got my conclusion (not sure if it is 
    > correct though) here: 
    > 1. There are two separate buffers of each Surface object. According to 
    > SDK, they were called "front buffer" and "back buffer". 

    > 2. Android's Surface does not behaves like regular "double-buffer" 
    > system, which means: draw everything in back buffer and then flip the 
    > back buffer into the front buffer. 
    > What Android Surface does seems to be: draw in buffer A and flip it on 
    > the screen, then in next cycle, draw buffer B and flip it on the 
    > screen. As the result, the content visible on the screen comes from 
    > buffer A, B, A, B, A, .... I'm using buffer "A" and "B" here instead 
    > of "front" and "back" because I think they have equal role in 
    > rendering cycle. 

    > 3. The Surface buffer's alternate work style causes problem when I'm 
    > doing partial update (repaint only a portion of the Surface) for the 
    > performance purpose. Because one "lockCanvas-drawCanvas-unlockCanvas" 
    > cycle only update one buffer, the other one remains untouched, then 
    > when next "lockCanvas-drawCanvas-unlockCanvas" comes, it shows you an 
    > old content on the screen so that the flicker happens. 

    You are correct in your analysis. Something that the documentation 
    doesn't emphasis clearly is that with such a mechanism, your *must* 
    draw every single pixel of the Surface's back buffer each-time. In 
    essence, the back buffer is not preserved in post. This is a common 
    behavior  of hardware-accelerated graphics systems. 

    There is fact an API on the underlaying Surface object that allows to 
    update only a portion of the back buffer (but even then, every pixel 
    of that portion need to be redrawn). It is implemented by copying back 
    the former back buffer (now in the front) to the new back buffer 
    (formerly in the front). Unfortunately, this API is not exposed to 
    SurfaceView at the moment. I'm hoping to have this feature added 
    eventually. 

    > 4. My work around (works but with tremendous performance penalty) 
    > When I'm doing partial Surface update, I do the following thing in 
    > each rendering cycle: 

    The best solution available right now to solve this problem, is to do 
    all of your rendering into your own bitmap and simply copy it into the 
    back buffer: 

    - create a bitmap 
    - attach a canvas to it 
    - do the rendering into that canvas 
    - lockCanvas 
    - draw your bitmap into the backbuffer 
    - unlockAndPost 

    Note that this method involves an extra copy of the whole buffer size, 
    but it is in fact not slower than what it would have been if the 
    posting mechanism worked as you expected/suggested. 

    > 5. In order to improve my solution a bit, I try to use 
    > "s.unlockCanvas(b);" instead of "s.unlockCanvasAndPost(b);" because I 
    > really do not need to make the second buffer flipping, I just need to 
    > synchronize its content. However, unlockCanvas() generates a "Illegal 
    > argument" exception. I can not figure out the reason. 

    I will investigate the error you are reporting. However, this solution 
    would not have worked because unlockCanvas() is essentially a no-op, 
    it doesn't post the back buffer, which means it won't make it visible. 
    It is only intended to be used in very special situations. 
    > I have noticed someone has met the similar SurfaceView problem, see 
    > the following topic: http://groups.google.com/group/android-developers/browse_thread/threa... 
    > I'm not sure if someone has any better solution than mine? 
    > Is there a way to notify Surface that I would like to use a fixed 
    > buffer as front buffer? 

    There is no way to do that at the moment, but we might add this 
    functionality eventually. Note that in that case, your Surface will 
    suffer from tearing, so it won't be suited for Surfaces that do a lot 
    of animations. 

    I hope this helps. 

    -- 
    Mathias 
    Android Graphics

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值