简体   繁体   中英

Runnable concurrency

I am playing around with JMonkeyEngine. While doing this i play JavaFX MediaPlayer. This MediaPlayer takes a Runnable to handle what's to do, when the media finished:

mp.setOnEndOfMedia(new Runnable() {
 @Override public void run() {
}}

I want to do sth. like this:

mp.setOnEndOfMedia(new Runnable() {
    @Override public void run() {
     //   instance.toggleLists();
        initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
        detachChild(node);
        node = new TextureNode("mediaManagerTextureNode");
        node.init(app, mp);
        attachChild(node);
    }
});

this is working a couple of times, but finally i am running into some runtime error.

java.lang.IllegalStateException: Scene graph is not properly updated for rendering.
State was changed after rootNode.updateGeometricState() call. 
Make sure you do not modify the scene from another thread!
Problem spatial name: Root Node

Yeah, that's true. I am messing up that thread from the outside. As i am a little bit unused to this stuff... I don't need to do that thing at that location in that run method, it's just what has to be done,when this is running.

What is the best way to pass over the work so that my ordinary update call can do that housework ? I already tried to build in a flag, setting that to true and when true, updating that by the standard update call from the application itself, but somehow i ever run into this error. That didn't help me much.

The MediaPlayer just needs to tell my App "Hey! I'm ready! Give me a break and change me to something new!" That is, what is happening in that run method.

You can use Application.enqueue to make a Runnable run on the main thread in the next update - like so: (assuming app is a reference to the Application)

mp.setOnEndOfMedia(new Runnable() {
    @Override public void run() {
       app.enqueue(new Runnable() {
            @Override public void run() {
                initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
                detachChild(node);
                node = new TextureNode("mediaManagerTextureNode");
                node.init(app, mp);
                attachChild(node);
            }
       });
    }
});

If you're using Java 8, you can abbreviate this using lambda expressions:

mp.setOnEndOfMedia(() -> {app.enqueue(() -> {
     initMediaPlayer(mediaView, actualList.getPath()+actualList.getMediaLocation());
     detachChild(node);
     node = new TextureNode("mediaManagerTextureNode");
     node.init(app, mp);
     attachChild(node);
}});

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM