I'm creating a game in which I create custom racing tracks and storing them in a database as strings. I do this by drawing on Canvas, creating a WritableImage by using snapshot, and then using a PixelReader to read the pixels one by one, storing a different character for every color (which in the game, is a different object eg. starting point, finish line, wall etc).
Everything is working fine on every first racing track I create, but on the other times I press the button to save a racing track (even if I exited the stage I was before and I'm in a new stage), I get this exception:
java.lang.IllegalStateException: Resource obsoleted too many times
at com.sun.prism.impl.ManagedResource.contentsNotUseful(ManagedResource.java:461)
at com.sun.prism.impl.BaseTexture.contentsNotUseful(BaseTexture.java:278)
at com.sun.javafx.sg.prism.NGCanvas.renderStream(NGCanvas.java:819)
at com.sun.javafx.sg.prism.NGCanvas.renderContent(NGCanvas.java:578)
at com.sun.javafx.sg.prism.NGNode.doRender(NGNode.java:2043)
at com.sun.javafx.sg.prism.NGNode.render(NGNode.java:1951)
at com.sun.javafx.tk.quantum.QuantumToolkit$18.draw(QuantumToolkit.java:1318)
at com.sun.javafx.tk.quantum.QuantumToolkit$18.run(QuantumToolkit.java:1354)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:129)
at java.lang.Thread.run(Thread.java:745)
I think it has to do with the snapshot not being full rendered but I don't know how to fix the issue.
I've tried starting a new thread and used "Thread.sleep(1000)" just to give it some time to finish rendering as I saw in https://community.oracle.com/thread/2579185
but it doesn't change anything.
Edit: Here's an SSCCE
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class ExceptionClass extends Application {
Canvas c;
GraphicsContext gc;
WritableImage temp;
int x = 0, y = 0;
@Override
public void start(Stage primaryStage) {
c = new Canvas(400, 400);
gc = c.getGraphicsContext2D();
gc.setStroke(Color.BLACK);
gc.setLineWidth(5.0);
temp = c.snapshot(null, temp);
Button btn = new Button("Damn you, stupid exception!");
btn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println("Altering the canvas...");
gc.strokeOval(x, y, 20, 20);
PixelWriter pr = gc.getPixelWriter();
pr.setColor(x + 10, y + 10, Color.RED);
temp = c.snapshot(null, temp);
x += 20;
y += 20;
}
});
StackPane root = new StackPane();
root.getChildren().addAll(c, btn);
Scene scene = new Scene(root, 800, 800);
primaryStage.setTitle("Exception!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
My assumption was wrong. It turns out that the PixelWriter I create is causing this exception. I didn't mention it before because I thought it was irrelevant, it's job is to just change the color of 1 pixel to indicate the starting point of my game, that's why it has to be called only when I save a track.
I would still like to know why this exception is thrown :)