2
\$\begingroup\$

I want a resized bitmap item to move over the screen into a house. This basically works, but the movement is not fluent and is stuttering. Since I always have to draw both the resized background and the house due to some alphas (both are exactly as big as the screen), the animation runs very slow, because invalidate() is no fast enough. At every bitmap move, invalidate() is being executed.

This is a very simplified example of my view to show what I'm doing.

public class GameView extends View implements ValueAnimator.AnimatorUpdateListener
{
    //more code

    @Override
    protected void onDraw(Canvas canvas)
    {
        canvas.drawBitmap(ResizedBitmapMapping.getBackground(), 0f, 0f, null);
        canvas.drawBitmap(item.getBitmap(), item.getXY().getX(), item.getXY().getY(), null);
        canvas.drawBitmap(ResizedBitmapMapping.getHouse(), 0f, 0f, null);
    }

    @Override
    public void onAnimationUpdate(ValueAnimator animation)
    {
        invalidate();
    }

    public void setActive()
    {
        item = new Item(ResizedBitmapMapping.getItem());
        XYHolder startXY = new XYHolder(0f, height);
        XYHolder endXY = new XYHolder(width * 2 / 3, height / 4);

        animator = ObjectAnimator.ofObject(car, "xY", new XYEvaluator(), startXY, endXY);
        animator.setDuration(2000);
        animator.addUpdateListener(this);
        animator.setRepeatCount(ObjectAnimator.INFINITE);
        animator.start();
    }

    //more code

}

My questions: Is the concept of drawing basically wrong? If yes, how does an efficient drawing concept look like? If the concept is right, is it just a case of optimizing like drawing just "rects" instead of the whole background and house or something?

\$\endgroup\$
4
\$\begingroup\$

When you want to draw something fast on the Android GUI don't use the View.onDraw() method. It is too slow. Generally everything is done one the main(gui)-Thread, including each onDraw() of each View. And the time of the calls to each .onDraw depend on everything else on the main thread. To be fast you want to draw onto a canvas on a separate thread (with the help of a SurfaceView). I recommend to look at the Drawing and Canvas topics in the Android Developer documentation: http://developer.android.com/guide/topics/graphics/2d-graphics.html.

Edit: Well I can't say much without looking at your new code and I have no own code available, I use this technic on more static canvas. On another stackoverflow forum there is a good answer, with working code (tested by myself before writing here) with a smooth animation of a ball and a moving background. I copy the explanation here: https://stackoverflow.com/questions/4938822/how-can-i-use-the-animation-framework-inside-the-canvas:

The Android animation class applies to objects such as views and layouts. The canvas is just a surface for drawing which is either part of a View or linked to a bitmap. In onDraw in a custom view only one frame is drawn at the time until next invalidate is called, which means that you have to draw your animation frame by frame. Here is an example of bouncing ball which rotates, which you may find useful.

When this is not smooth enough, and this will happen, when start using multiple moving objects (for instance 30), you should start thinking about switching to Open GL.

\$\endgroup\$
  • \$\begingroup\$ I modified it and use a SurfaceView with a worker thread now, but it doesn't give any approvement. This is exactly as slow as drawing on the view itself. \$\endgroup\$ – Bevor Jun 30 '14 at 19:39
  • \$\begingroup\$ please, see new edit. HTH. \$\endgroup\$ – Minsky Jul 1 '14 at 10:52
  • \$\begingroup\$ I found a suitable solution. See my answer. I upvote yours due to your efforts to find a solution. \$\endgroup\$ – Bevor Jul 1 '14 at 19:17
2
\$\begingroup\$

I found a solution which works for my purposes since I don't use many bitmaps on the canvas. It's absolutely fluent when I invalidate() just once when all bitmaps (background and so on) have been loaded and then in onAnimationUpdate() I only partially invalidate the canvas by this method:

invalidate(int l, int t, int r, int b);

That means I only invalidate the rect around the moving bitmap(s). Since they lie close together, I don't get such a big "dirty rect" and it's very fluent. If the bitmaps are scattered around the whole surface, the trick would probably be to invalidate each bitmap after another (not tested yet). That would mean that one complete move of all bitmaps would take as long as every single bitmap has been invalidated. It's some kind of a juggling act because you have to think about what is slower: A very big dirty rect invalidated just once or many invalidates of several dirty rects.

By the way: I wonder how all the games on Android are designed. They are always absolutely fluent. Do they all use OpenGL?

\$\endgroup\$
  • \$\begingroup\$ Great that it works for you now!. Most use a middleware engine, which does offer a rendering pipleline. For instance: LibGDX, MOAI, Unity, Corona2D, Cocos etc. Those engines work often across multiple platforms offering a wrapper/generator for each platform. Despite this I think, it is possible to do everything via OpenGL directly in a native Java Android app. \$\endgroup\$ – Minsky Jul 2 '14 at 6:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.