How to avoid image flickering when drawing on canvas.
Below code keep on running for images.The next image comes sliding from top but the previous image keep on flickering at back.I just want the previous image to become static.
void drawscreen()
{
SurfaceHolder holder = getSurfaceHolder();
try
{
Backgroundcanvas = holder.lockCanvas();
if (Backgroundcanvas != null)
{
if (top == true)
{ slide_from_top(); }
}
}
finally
{
if (Backgroundcanvas != null)
holder.unlockCanvasAndPost(Backgroundcanvas);
}
mHandler.removeCallbacks(mUpdateDisplay);
if (mVisible && count)
{
mHandler.postDelayed(mUpdateDisplay, interval);
count = false;
}
else
{
mHandler.postDelayed(mUpdateDisplay, 100);
}
}
I was also getting same problem, image flickering when drawing on canvas .
What I have done is making my worker thread(Not UI Thread) sleep for 10mlsec every time after using canvas drawing, and this time flickering is gone,
You can try this trick...
Clear canvas after each thread ends.
Just call Canvas.drawColor(Color.BLACK), or whatever color you want to clear your Canvas with.
Related
I'm trying to develop a game using a transparent canvas and a surfaceView, I use the canvas to paint and it works fine.
Now I want to add objects that will move on the screen, for example bouncing balls.
I want to use a new thread for the balls, (because otherwise if it's the same thread of the surfaceView it doesn't move smoothly ).
So I'm having trouble of doing this.
Can you please advise me how and when should I send the same canvas to a new ball object and then return it back to the surfaceview.
I'm not sure what the best way to handle this is,
I tried using a ball as a view in the xml layout, and it worked perfect on another thread but it doesn't make sense to create 1000 views when I can just draw them on a canvas.
Any insight will be helpful!
This is my code:
public class SurfaceMyPaint extends SurfaceView implements Runnable
{
Thread t;
SurfaceHolder holder;
Bitmap brush;
boolean isItOk = false;
public SurfaceMyPaint(Context context)
{
super(context);
holder = getHolder();
initial();
}
public void initial()
{
brush= BitmapFactory.decodeResource(getResources(), R.drawable.brush2);
}
public boolean onTouchEvent(MotionEvent event)
{
if(event.getAction()== MotionEvent.ACTION_DOWN)
{
x= event.getX();
y= event.getY();
}
if(event.getAction()== MotionEvent.ACTION_MOVE)
{
x = event.getX();
y= event.getY();
}
return true;
}
public void run()
{
while (isItOk == true)
{
if (!holder.getSurface().isValid())
continue;
myCanvas_w = getWidth();
myCanvas_h = getHeight();
if (result == null)
result = Bitmap.createBitmap(myCanvas_w, myCanvas_h, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(result);
canvas = holder.lockCanvas(null);
c.drawBitmap(brush, x - (brush.getWidth() / 2), y - (brush.getWidth() / 2), null);
canvas.drawBitmap(result, 0, 0, null);
// How can I add this here: Ball ball = new Ball (canvas)????
holder.unlockCanvasAndPost(canvas);
}
}
public void pause(){
isItOk = false;
while (true){
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
break;
}
t=null;
}
public void resume()
{
isItOk = true;
t = new Thread(this);
t.start();
}
}
Summarizing your rendering code:
Create a screen-sized off-screen bitmap, which you hold in a variable called "result" that isn't declared in the code you show. I assume this is a field, and the allocation only happens once?
Each time, you create a new Canvas for that Bitmap.
You draw on the Bitmap, with drawBitmap().
You copy the Bitmap to the Surface, with drawBitmap().
You want to add a step #5, "draw Ball".
The obvious place to do the ball drawing is in step #3, but I'm going to assume you're not doing it there because that has some relatively static content that you update infrequently but want to blend in every frame.
That being the case, you should just draw the balls onto the Canvas you got back from SurfaceHolder. What you must not do is store a reference to the Surface's Canvas in the Ball object itself, which it appears you want to do (based on new Ball(canvas)). Once you call unlockCanvasAndPost() you must not use that Canvas anymore.
I don't really see an advantage to using multiple threads with your current code. If the "background" Bitmap were also changing you could render that with a different thread, and merge in the current version when you draw, but I suspect that will be more trouble than it's worth -- you will have to deal with the synchronization issues, and I don't think it'll solve your non-smoothness.
I've created a custom view that draws via onDraw() overridden method some shapes. This view is scrollable so every time user navigates in the Activity, onDraw() method has called and all the canvas is drawn. In the onDraw() method there are some statements making some hard calculations so my intent is to draw, when user scrolls the view, only the part that were invisible and now, for the scrolling, they are visible.
How can I draw only the part that are visible in my custom view?
#Override
protected void onDraw(Canvas sysCanvas)
{
super.onDraw(sysCanvas);
if(!giaDisegnato) //If I've never drawn before, let's draw
{
if(!listaTl.isEmpty())
{
toDisk= Bitmap.createBitmap(w,h,Bitmap.Config.RGB );
canvas = new Canvas(toDisk);
canvas.drawColor(Color.WHITE);
p.setStyle(Paint.Style.FILL_AND_STROKE);
p.setAntiAlias(true);
p.setStrokeWidth(1);
for(TimelineGrafica t : listaTl)
{
if(inseritaLaPrima)
y = ySalvata + this.yAngoloDestroGiu + DISTANZA_FRA_TIMELINE;
p.setColor(t.getColor());
disegnaPunta(canvas,p,t);
disegnaRettangolo(canvas,p,t);
disegnaGrain(canvas,p,t);
disegnaFatti(canvas,p,t);
inseritaLaPrima = true;
}
y = ySalvata;
inseritaLaPrima = false;
sysCanvas.drawBitmap(toDisk,0,0,p);
}
requestLayout();
giaDisegnato = true;
}
else
{
//Here I've already drawn. So I'd like to redrawn the part of the view that now
//is visible.
sysCanvas.drawBitmap(toDisk,0,0,p);
}
}
Due to the language, it is difficult to know precisely what you are doing.
However, you can check the canvas to know whether you should draw or not using quickReject.
Example:
if(canvas.quickReject(boundingRect, EdgeType.BW)) {
return;
}
I'm trying to add different animations using matrix.setRotate (45), etc. to the Live Wallpaper, but it didn't work. All it did was showing the pictures in 45 degrees. I thought it would be rotating to 45 degrees?
I would like to add different animations to the slideshow live wallpaper like rotation, fading, translation, transformation, scaling, etc.
I even tried
matrix.setRotate(90);
matrix.setTranslate(100, 100);
but the pictures showed up very weird. Perhaps, there was any animation....
I know how to apply the animations from res/anim/animation.xml to NONE live wallpaper, but I can't seem to find a way to apply this animation.xml to the Live Wallpaper.
Is possible and easy way to apply animations to Live Wallpaper?
Thank you very much for your help in advance.
Java Code:
......
.....
....
private void drawFrame() {
// TODO Auto-generated method stub
final SurfaceHolder holder = getSurfaceHolder();
Canvas c = null;
try {
c = holder.lockCanvas();
if (c != null) {
drawPirate(c);
}
} finally {
if (c != null)
holder.unlockCanvasAndPost(c);
}
mhandler.removeCallbacks(drawrunnable);
if (mVisible) {
mhandler.postDelayed(drawrunnable);
}
}
private void drawPirate(Canvas c) {
// TODO Auto-generated method stub
Bitmap icon;
Matrix matrix = new Matrix();
matrix.setRotate(45);
icon = BitmapFactory.decodeResource(getResources(),pirates[i]);
c.drawBitmap(icon, matrix, null);
icon.recycle();
}
}
I'm not familiar with live wallpapers, but hopefully I can answer some of your other questions.
setRotate is not an animator, it rotates to its setting all at once
Good way to do this would be to create a thread for your drawFrame() and have it loop calling drawPirate(c), while incrementing the rotation value each time, so that you draw your image at setRotate(1), setRotate(2), etc until 45. You might want to look at the JetBoy android sample code for this kind of an implementation.
It is not good practice to allocate new things and decodeResources in the draw method. When you make multiple calls to it, it will have to create the new things every time and will slow things down a lot.
I'm working on an android app of mine, but there is a small problem I'm having that is limiting its functionality. I'm using the android canvas to draw an animation to the screen (for a live wallpaper), but whenever I try drawing using Canvas.drawColor() with a color like #01ffffff (the last two digits are the alpha level), the canvas gets darker! How can that be? I'm drawing white over the canvas, albeit a very transparent white, but still a white. How can it be getting darker?
The color is getting drawn every frame. It is used to provide a fade to white animation, but it doesn't fade to white.
My code:
public class MyWallpaperService extends WallpaperService {
...
private void draw() {
handler.removeCallbacks(drawRunner);
SurfaceHolder holder = getSurfaceHolder();
Canvas canvas = null;
if (holder.getSurface().isValid()) {
if (visible) {
handler.postDelayed(drawRunner, refreshRate);
}
try {
canvas = holder.lockCanvas();
if (canvas != null) {
canvas.drawColor(backgroundColor);
}
} finally {
if (canvas != null)
try{
holder.unlockCanvasAndPost(canvas);
} catch (Exception e) {
e.printStackTrace();
}
}
}
...
}
The draw() method is used to draw my wallpaper to the screen and within it has a call to canvas.drawColor(). The variable named backgroundColor is initialized to the color #01ffffff. So does anyone know why this is happening and what I can do to fix this? Thanks! (And any syntax errors in the code, like missing brackets, are probably due to my poor copy and pasting skills.)
Android color resources are defined with the first two digits as the transparency values. That may be your problem (as retailcoder suspected).
my live wallpaper doesn't slide smoothly most of the time on home screen change.
there is not a complicate coding for the position of background. it just use the xpixles that located on the onoffsetschanged method to adjust the x position of the wallpaper.
sometime it slide well same as in the sun rise live wallpaper app. but most of the other time it slide.. dunno how to describe it but its like a static sharp move. is there any idea about that guys.
best regards.
private void drawS() {
final SurfaceHolder holder = getSurfaceHolder();
canvas = null;
try {
canvas = holder.lockCanvas();
if (canvas != null) {
background = BitmapFactory.decodeResource(getResources(),
R.drawable.background);
canvas.drawBitmap(background, mXPixels, mYPixels, null);
}
}
finally {
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
handler.removeCallbacks(runnableS);
if (visible) {
handler.postDelayed(runnableS, 25);
}
}
try to avoid resource creation in draw routine; remove this from drawS() function:
background = BitmapFactory.decodeResource(getResources(),
R.drawable.background);
and put it wherever you initialize your stuff and just use reference to background Bitmap later on.
If you take a look at logcat you'll see that there's a lot or resource shuffling and memory management going on (allocating memory for your resource, decoding bitmap image in it etc) every time you call your drawS(); ie every time you draw your background...
Cheers,
Ivica
I encountered the same problem and solved by following Ivica suggestion.
I moved the bitmap creation line inside the surface creation sub:
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
mybackground = BitmapFactory.decodeResource(getResources(), R.drawable.mybg);
}
In this way the sliding is very fluent