Reputation: 2109
I have created a class that extends SurfaceView in order to cycle a series of ARGB bitmaps. This mostly works, except that the state of the underlying bitmap is (usually, but not always) preserved for each new frame.
In other words, if the first frame I display is opaque, and subsequent frames are transparent, then the opaque pixels from the original frame are not cleared out when the new frames are drawn.
This behavior confuses me, because the documentation for SurfaceHolder.lockCanvas() specifically states:
"The content of the Surface is never preserved between unlockCanvas() and lockCanvas(), for this reason, every pixel within the Surface area must be written."
If I just had a solid background, then calling canvas.drawARGB(255,0,0,0) succeeds to clear it to black...but I want to have a transparent background, and I can't clear it to a transparent color, because canvas.drawARGB(0,0,0,0) has no effect.
import java.util.ArrayList;
import java.util.Random;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
/*
* Accepts a sequence of Bitmap buffers and cycles through them.
*/
class AnimatedBufferView extends SurfaceView implements Runnable
{
Thread thread = null;
SurfaceHolder surfaceHolder;
volatile boolean running = false;
ArrayList<Bitmap> frames;
int curIndex = 0;
public AnimatedBufferView(ArrayList<Bitmap> _frames, Context context)
{
super(context);
surfaceHolder = getHolder();
frames = _frames;
}
public void onResume(){
running = true;
thread = new Thread(this);
thread.start();
}
public void onPause(){
boolean retry = true;
running = false;
while(retry){
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Override
public void run()
{
// TODO Auto-generated method stub
while(running)
{
if(surfaceHolder.getSurface().isValid())
{
Canvas canvas = surfaceHolder.lockCanvas();
//clear the buffer?
//canvas.drawARGB(255, 0, 0, 0);
//display the saved frame-buffer..
Matrix identity = new Matrix();
Bitmap frame = frames.get(curIndex);
canvas.drawBitmap(frame, identity, null);
surfaceHolder.unlockCanvasAndPost(canvas);
curIndex = (curIndex + 1) % frames.size();
try {
thread.sleep( 100 );
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
Upvotes: 1
Views: 5833
Reputation: 1616
The google doc says the right thing...since you re locking the pixels of the surface and there are two buffers because android uses tripple or double buffering depending on the speed of the drawing calls it can draw on one frame one buffer with whatever content you have filled it in drawing calls before and on the next it could draw another buffer with another content so you might lock the surface that is being made of data from another buffer....
so better overwrite everything before you draw anything like you said for example with proter duff mode and clear color or just a balck color with canvas.drawColor(Color.BLACK);
Upvotes: 0
Reputation: 2109
Ok, discovered the problem was the default Porter-Duff drawing mode that made drawing a transparent color impossible. Just have to change mode. ie,
Canvas canvas surfaceView.lockCanvas();
canvas.drawColor(0, Mode.CLEAR);
Upvotes: 5
Reputation: 6052
This one confused me for a while. Basically, you're going to have to redraw the whole screen every frame. This is because when you lock the canvas, what you get is a canvas that is two frames behind, and not the last frame that was posted. This is due to the way the frames are buffered. There are only two buffers, the one that is currently being shown, and the one that got posted before the current one. When you lock the canvas you get the one that isn't currently being shown (which means you get a canvas that is a frame behind).
This is why you might hear people refer the buffer as a swap buffer, because the currently display screen gets swapped with the one that you draw everything on. This means you never really get back the latest buffer.
Hope that makes some sort of sense to you.
Upvotes: 2