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?
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.