Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Draw on a canvas with delay - "make onDraw() slow down"

I use functions for canvas like drawCircle and drawPoint in android. This works fine.

But the problem now is to draw these different items with a delay, so it looks like an animation.

What kind of mechanism should I use? Have tried with async but I dont like that way of doing it.

Should I use some kind of timer that just draw with an interval or is there other clever ways to do this?

like image 378
FooBar Avatar asked Oct 10 '12 18:10

FooBar


Video Answer


2 Answers

I use this strategy, first I declare a Handler and a Runnable that way:

    private final Observable mObservable = new Observable();
    private final static int TIME_STEP_MS = 5;
    private final Handler mHandler = new Handler();
    private final Runnable mTimeManager = new Runnable() 
    {
        public void run() 
        {
            mObservable.notifyObservers(TIME_STEP_MS);
            mHandler.postDelayed(mTimeManager, TIME_STEP_MS);
        }
    };

Then when I want to start my time manager I just call the mTimeManager.run() and it will start to notify my Observer s (previously added) periodically.

If you need for some reason stop the timer or something you just do that:

    mHandler.removeCallbacks(mTimeManager);

[ EDIT - More complete code ]

Ok than let's make it clearer, first I made a custom Observable object like that [that's optional]:

    private final Observable mObservable = new Observable()
    {
        public void notifyObservers()
        {
            setChanged();
            super.notifyObservers();
        };

        @Override
        public void notifyObservers(Object data) 
        {
            setChanged();
            super.notifyObservers(data);
        };
    };

the reason for that is just because I can't call setChanged() outside Observable class - it's protected, if it's not changed it doesn't notify any observer.

The other declarations keep the same as shown before, now I need to start this TimeManager somewhere, my app is a LiveWallpaper and I make all rendering stuff into a class that extends a Thread but you don't need that necessarily, I made a method called resumeDrawing(), this one is called right after super.start(); at my @Override of public synchronized void start() from Thread class, the method looks like that:

    public void resumeDrawing()
    {
        if (!mTimeManagerRunning) // just a boolean field in my class
        {
            System.err.println("Resuming renderer."); // just for debug
            mTimeManager.run();
            mTimeManagerRunning = true;
        }
        else
        {
            System.err.println("Renderer already running."); // just for debug
        }
    }

and it's dual:

    public void pauseDrawing()
    {
        if (mTimeManagerRunning)
        {
            System.err.println("Pausing renderer.");
            mHandler.removeCallbacks(mTimeManager);
            mTimeManagerRunning = false;
        }
        else
        {
            System.err.println("Renderer already paused.");
        }
    }

Ok, now we can start and stop the time manager, but who's listening? Nobody! so let's add'em: On the constructor of my Renderer I add some Observer s to my mObservable object, one of those is the Renderer itself, so my renderer extends Thread and implements Observer:

    @Override // from Observer interface
    public void update(Observable arg0, Object arg1) 
    {
        mElapsedMsRedraw += (Integer) arg1; 

        if (mElapsedMsRedraw >= mDrawingMsPerFrame)
        {
            mElapsedMsRedraw = 0;
            drawEm(); // refresh the canvas and stuff
        }
    }

to add observers you simply do mObservable.addObserver(THE_OBJECT - Implements Observer)

you can see that I don't re-render my stuff each time I'm notified, that's because I use this TimeManager for other thinks than just refresh the Canvas like updating the position of the objects I want to draw just internally.

So, what you need to slow down the drawing is to change the way your objects change internally while the time passes, I mean your circles and points etc, or you can chance your time step, I recommend the first one.

Was it clearer? I hope it helps.

like image 186
HericDenis Avatar answered Oct 11 '22 12:10

HericDenis


I would use a timer, or create Animations. You can create Animations that will do all sorts of things including changing transparency over time.

Here's the Android Documentation for Animation Resources

like image 32
mgidell Avatar answered Oct 11 '22 13:10

mgidell