Okay so far when I have used SurfaceView I would override the draw method and then call it from a seperate thread. However, recently I tried to not override it but simply make all my canvas drawing calls in a custom method, and it worked. I would just do all my drawing the same way but instead of all the code being in overridden draw method, I would just put it all in another method and it worked anyways. So whats the point of overriding anything? I honestly still don't know how all the drawing works behind the scenes as its not explained...
For SurfaceView as you noticed yourself it makes no difference. There's no point of overriding draw and then calling it yourself from the separate thread.
The SurfaceView only have the method there because it inherits it from the View class, but because you're, in a separate thread, acquiring the lock to the canvas, drawing and then releasing, it doesn't matter if you pass it to the draw method, if you use directly on the thread run or some other Runnable
Maybe one could argue that it's more organised (and do never underestimate the importance of a well organised code), but it's not a necessity.
Related
I have made a "2048 game" with java in Eclipse . All things is good and work correctly, even the animation of cells that move in 4 directions.
But the problem is, that the animation does not work fine & smooth, I think because of heavy processing load.
I have made a class that extends ImageView. and I have overridden the
onDraw() method. Then in another method and in a thread, I call the postInvalidate() method frequently for the animation (so the onDraw() method is called frequently).
My algorithm in the onDraw() method is fine and my animation runs correctly but I think using this way (using ImageView class and calling onDraw() method frequently) is not an accurate way, because the onDraw() method redraws everything unnecessarily. Some things in this game are fix and do not need to be redrawn, so this way the process is heavy and I don't like this.
Is there another way for this game, than drawing the page frequently for animation without jumping? thank's for your answer .
I have created a custom view to be shown in the action bar. It mostly works except sometimes on start I see a mirror copy of whatever I draw. The copy overlaps the original one but a few pixels away.
My onDraw() override is quite simple. All it does is draws an image that is centered in the canvas.
I am a bit confused. Am I expected to clear the canvas first in onDraw() method? Thank you in advance for your help.
It is confusing, but you'll notice in the custom view samples (that come with the sdk), the onDraw() method first calls canvas.drawColor() before anything else.
I assume it's not done automatically because it would be wasteful in the case where what you were drawing filled the entire view anyway. I just wish it was more clear that it is necessary in most cases.
Here is what I found out that others may find useful. If you set a background using setBackground(), the framework will actually draw the background before calling onDraw(). This background is drawn in the center. I too was drawing the background in onDraw() but I was drawing it from top-left. Hence, I was seeing the ghost image.
As Krylez mentioned, you may wish to call drawColor() as your first call in onDraw().
What I did was overrode setBackground() and its variations, and stored the background bitmap in a local variable.
Regards,
Peter
How do I call onDraw() on my class extending GLSurfaceView. I need the canvas for drawing the gestures of the user. (FingerPaint.java logic). Mean while I need the onDrawFrame() of the renderer to be called for other effects. I can manage the calls to both the methods by maintaing a flag. I am calling invalidate() but that too is not able to call the onDraw(). GLSurfaceView extends View so I thought I can override onDraw() and can call it by calling invalidate(). Please Throw some light. Thanks in Advance Krishna :)
Try calling requestRender () from your GLSurfaceView.
Obviously this works best when setting rendermode to "RENDERMODE_WHEN_DIRTY".
And that means you won't be rendering continuously, so that may interfere with the "constant" rendering required for your effects.
I think the best solution would be to split the rendering up between 2 overlaying surfaces and 2 renderers. Request the bottom surface (fingerpaint surface) to render a frame whenever the user interacts, and on the top one (gfx surface) you render continuously. Or swap this around... whatever works best.
Just call invalidate() and onDraw() will be called, just like normal View. The canvas is drawn on top of the GLES viewport.
So far I couldn't implement invalidate(Rect dirty). The whole view is redrawn always.
It is needed to put setWillNotDraw(false) before drawing.
Is it a good programming practice to call invalidate() inside onDraw()?
As per my understanding, calling invalidate() inside onDraw() is expensive and is not required if there is no change to the canvas.
Is invalidate() equivalent to an asynchronous version of onDraw()?
As per my understanding, they are equivalent. Correct me if I am wrong. Thank you.
Only call invalidate() if your data has changed and needs to be redrawn. You generally don't do this in onDraw(), because at that point you are drawing your current data, not changing it. (There are some cases where you may want to do this, such as for running animations, but generally I would recommend instead using a delayed message to control your own timing of the updates.)
I'm developing chess game for Android (androidchess.appspot.com). If I want to add animations, should I use custom View extending Canvas (I do this now), or custom View extending SurfaceView?
I haven't tried using a View to extend Canvas, but for my game I'm using the same method as the LunarLander example game:
public class CustomView extends SurfaceView implements SurfaceHolder.Callback
The usefulness of this is that it gives you handles for SurfaceHolder (so you can call up the canvas which is drawn to the screen), and the callbacks for surfaceCreated, surfaceChanged and surfaceDestroyed. That lets you do things like drawing a custom animation as soon as the surface is available or make sure that you don't try to draw to the canvas after it has been deactivated. Looking through LunarLander should show you how to use these properly.
Edit: I remembered another reason why using a SurfaceHolder was useful. This is because, as I mentioned above, it lets you get direct access to the canvas which is drawn to the screen. With a SurfaceHolder this is done not by overriding onDraw but by using something like Canvas canvas = mSurfaceHolder.lockCanvas(). (See LunarLander for exact syntax). The reason this is important is because it lets you control exactly when the drawing happens. If you can only work by overriding onDraw(), then the drawing doesn't happen until your program reaches a 'waiting' phase. In other words, you can't use invalidate() and onDraw() in a loop because the drawing won't happen until the loop finishes. And since you're likely to use loops for things like drawing a piece moving across the screen, this becomes a problem.
Note: It may be possible to avoid this problem by using multiple threads. I simply haven't tried that since it isn't required for my game; the only animation is has is fixed-length animations in response to user input rather than something continuously moving in the background, so I haven't experimented with multiple threads yet.