Reusing Runnable for handler.postDelayed()

1.1k Views Asked by At

I am trying to avoid garbage creation by reusing runnable. However, I am stuck on how to implement this correctly.

Here is my runnable wrapper class:

    public class RotateRunnable implements Runnable {

    Maze maze;
    int i;
    int steps;
    int originalAngle;
    int dir;

    public RotateRunnable(Maze maze) {
        this.maze = maze;
    }

    public void setRunnable(int i, int steps, int originalAngle, int dir) {
        this.i = i;
        this.steps = steps;
        this.originalAngle = originalAngle;
        this.dir = dir;
    }

    @Override
    public void run() {
        maze.setIsRotateRunning(true);
        maze.setAngle(originalAngle + dir*(90*(i+1))/steps);
        maze.rotateStep();
    }

}

And here is where I have implemented it:

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

The commented out section is working code. The problem I am running into is setting the variables inside rotateRunnable before postDelay() is called. Right now that is not working as rotateRunnable is likely only executing the last variables that are set. This is because smoothAnimateRotate() is executed inside a for-loop which updates the variables very quickly.

How do I make setting the variables part of the run method so that when run is executed later, it is executing with the correctly set variables?

1

There are 1 best solutions below

0
On BEST ANSWER

In fact, call handler.postDelayed method is actually push a message into the MessageQueue,and set the message's callback with your runnable object. From your description, you called smoothAnimateRotate method inside a for-loop very quickly, this may only take a very short time , even less than 25ms, so when messageQueue start poll messages and excute rotateRunnable,only executing the last variables that are set.

you can allocate a ArrayList object to cache all the variables like below

public class RotateRunnable implements Runnable {

public static int index = 0;
public static ArrayList<RotateNode> rotateNodeList = new ArrayList<RotateNode>();

Maze maze;
int i;
int steps;
int originalAngle;
int dir;

public RotateRunnable(Maze maze) {
    this.maze = maze;
}

public void setRunnable(int i, int steps, int originalAngle, int dir) {
    RotateNode node = new RotateNode();
    node.i = i % 100;
    node.steps = steps;
    node.originalAngle = originalAngle;
    node.dir = dir;
    rotateNodeList.add(i % 100, node);
}

@Override
public void run() {
    RotateNode node = rotateNodeList.get(index % 100);
    maze.setIsRotateRunning(true);
    maze.setAngle(node.originalAngle + node.dir*(90*(node.i+1))/node.steps);
    maze.rotateStep();
    index ++;

}

}

public class RotateNode {
int i;
int steps;
int originalAngle;
int dir;

}

to avoid arraylist's size infinite increace, i assume the rotate animation is 100 steps per circle, you can replace it with your steps per circle.Hope this works for you.