Handler postDelay() leading unexpected variable changes

260 Views Asked by At

I am working on a game and I am using postDelay() to make the animations smoother. A problem I am running into is that if I execute the method with postDelay() in it, the variables that the method operates on no longer gets changed in unexpected ways. This leads to weird behavior such as the bitmaps not drawing properly.

Here are the troublesome parts:

       synchronized private void rotate(int dir) {
            final int originalAngle = angle; //angle is the suspicious variable
            final int steps = 4;

            for (int i = 0; i != steps; i++) {
                smoothAnimateRotate(i, steps, originalAngle, dir);
            }
            finishAnimateRotate(steps);
        }

        private void smoothAnimateRotate(final int i, final int steps, final int originalAngle, final int dir) {
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    angle = originalAngle + dir*(90*(i+1))/steps;
                    rotateStep();
                }
            }, 100 * (i + 1));
        }


        private void rotateStep() {
            angle = (angle+1800) % 360;
            viewdx = (int) (Math.cos(radify(angle))*(1<<16));
            viewdy = (int) (Math.sin(radify(angle))*(1<<16));
            moveStep();
        }

        private void moveStep() {
            notifyViewerRedraw() ;
            try {
                Thread.currentThread().sleep(25);
            } catch (Exception e) { }
        }

When rotate() is called very quickly, I think the variable angle somehow gets messed up. This doesn't happen when I call rotate() about one second apart, but if I do it very quickly, the angle, which is only suppose to be either 0, 90, 180, or 270 gets changed to 45 degrees or something else. I can't figure out why and debugging hasn't provided fruitful results. So how do I make sure angle does get modified in such unexpected manner?

1

There are 1 best solutions below

0
On

I fixed it. I put a boolean called isRunning inside the Runnables and switched it on and off.

synchronized private void rotate(int dir) {
    final int originalAngle = angle;
    final int steps = 4;

    if (!isRunning) {
        for (int i = 0; i != steps; i++) {
            smoothAnimateRotate(i, steps, originalAngle, dir);
        }
        finishAnimateRotate(steps);
    }
}

private void smoothAnimateRotate(final int i, final int steps, final int originalAngle, final int dir) {
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            isRunning = true;
            angle = originalAngle + dir*(90*(i+1))/steps;
            rotateStep();
        }
    }, 100 * (i + 1));
}

private void finishAnimateRotate(final int steps) {
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            rotateFinish();
            isRunning = false;
        }
    }, 100 * (steps + 1));
}