Runnable concurrency - java

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);
}});

Related

Vaadin 8: How to update a label value on a modal form from another thread

I am using vaadin 8, and I need to update a label value on a modal.
In the listing below, a label value is inside a while(true) cycle being executed from another Thread:
modal.show();
modal.getUI().access(new Runnable() {
#Override
public void run() {
while(true) {
sleep(1000)
....
break_condition;
break;
}
modal.getLabel().setValue("xxxx")
}
});
During the process, the screen will freeze and the modal windows appears at the end with the label value modified. Is it possible to do without freezing the screen?
A possible solution...
class TaskCycle implements Runnable {
MyModal modal;
public TaskCycle(MyModal modal){
this.modal = modal
}
#Override
public void run() {
while(true) {
sleep(1000)
....
break_condition;
break;
}
modal.getLabel().setValue("xxxx");
modal.getLabel().getUI().push();
}
}
MyModal modal = new MyModal();
modal.show();
TaskCycle r = new TaskCycle (modal);
Thread t = new Thread(r);
t.start();
In general, this solution works well but needs of the configuration of a "vaadin server-push" (see the officical documentation).
Unfortunately I am using Liferay 7 and the push server (of vaadin 8) does not work.
This solution in my case is not the best, because the modal is updated with the new values (provided by the thread), only if you perform a "resize" of the browser window/tab.
In order to "simulate" the resize it is possible to insert the function:
setPollInterval(1000);
UIEvents.PollListener poll = new UIEvents.PollListener(){
#Override
public void poll(UIEvents.PollEvent event) {
System.out.println("Poll interval start!!!!!");
}
};
UI.getCurrent().addPollListener(poll);
to remove listener:
UI.getCurrent().removePollListener(poll);
this is a good workaround for all users that can't use the push() function.
Try to relax the while loop execution introducing a sleep. This could avoid the screen to freeze:
Thread.sleep(50);

Java FX application stuck when Java opens Matlab

I'm making a program which sends some data to the Matlab and receives output from matlab. To do that, I used matlabcontrol library.
Problem
After I click Java FX application button to submit data, matlabcontrol opens Matlab for further calculations. But when java opens the matlab, Java FX application stuck with wait cursor.Then starts to work again after Matlab finishes the process of calculation.
What I did
public void runner()
{
Platform.runLater(new Runnable()
{
#Override
public void run()
{
firstFunc();
}
});
Platform.runLater(new Runnable()
{
#Override
public void run()
{
secondFunc();
}
});
}
public void firstFunc()
{
// This function controls UI while Matlab does it's calculations
double progress = 0.2;
progressLabel.setText(progress*100+"% Completed");
progressBar.setProgress(progress);
}
public void secondFunc()
{
// This method creates matlab connection and handle matlab
firstClass mainFunc = new firstClass(pathSelected);
mainFunc.func();
}
So I used Platform runLater to run two methods separately. But still my program stuck with wait cursor when Matlab starts to functioning.
I also used threads to run these functions in parallel. But had the same issue. How can I correct this. Any help?
Update
As described in this question, I did use service and task with countdownlatch. But still didn't get what I wanted. In there,
Service<Void> service = new Service<Void>() {
#Override
protected Task<Void> createTask() {
return new Task<Void>() {
#Override
protected Void call() throws Exception {
//Background work
final CountDownLatch latch = new CountDownLatch(1);
Platform.runLater(new Runnable() {
#Override
public void run() {
try{
//FX Stuff done here
firstFunc();
}finally{
latch.countDown();
}
}
});
latch.await();
//Keep with the background work
// I added matlab calling function here.
secondFunc();
return null;
}
};
}
};
service.start();
latch await and let background work to carry on. But in my case, my FX application shows a progress bar. So it should always update while background task happens. In here, it finishes FX task and moves to background task. I didn't get what I wanted. please help.
I had to use Service, Task and CountDownLatch to accomplish this task as I mentioned in Question Update part.
Also, I had to run another task inside the firstFunc, where I did update the progress. Like in this answer.

Animators may only be run on Looper threads Android

I'm trying to animate something when a task is completed. The problem here is I get this error message:
android.util.AndroidRuntimeException: Animators may only be run on Looper threads
at android.animation.ValueAnimator.cancel(ValueAnimator.java:1004)
at android.view.ViewPropertyAnimator.animatePropertyBy(ViewPropertyAnimator.java:965)
at android.view.ViewPropertyAnimator.animateProperty(ViewPropertyAnimator.java:921)
at android.view.ViewPropertyAnimator.alpha(ViewPropertyAnimator.java:735)
at com.design.zaton.prototypei.MainActivity$1$1.run(MainActivity.java:93)
at java.lang.Thread.run(Thread.java:761)
The app worked fine before with the same exact code but now it simply doesn't. I'm really confused.
Here's where the error happens:
new Thread(new Runnable() {
#Override
public void run() {
final String s = getGiphyViews(String.valueOf(mEdit.getText()));
runOnUiThread(new Runnable() {
#Override
public void run() {
result.setText(s);
}
});
loading.animate()
.alpha(0)
.setDuration(100);
done.animate()
.scaleY(1)
.scaleX(1)
.setDuration(300);
}
}).start();
The error outlines the loading.animate() method.
Thanks in advance!
runOnUiThread(new Runnable() {
#Override
public void run() {
//Your code
}
});
You have to execute the code in the UI Thread
Looper threads are threads in Android that permanently loop (or until you cancel them). They work in conjunction with Handlers which will post and send messages to Looper threads. Animators use heavy use of Looper threads because they perform their actions in repeated cycles. This allows the animator to not block after you press "start" so you can continue to perform other actions.
To further complicate matters, you most likely are performing animations on View objects. These can only be run on the main UI thread (which happens to be the biggest Looper thread of them all). So, you can not run these animations on separate threads like you are trying.
I think, there has been a solution for this using Handler. You can use postDelayed to minimal as 100 and run your animating tasks. In your case it would be:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
final String s = getGiphyViews(String.valueOf(mEdit.getText()));
runOnUiThread(new Runnable() {
#Override
public void run() {
result.setText(s);
}
});
loading.animate()
.alpha(0)
.setDuration(100);
done.animate()
.scaleY(1)
.scaleX(1)
.setDuration(300);
}
}, 100);
I had this problem today and above work resolved the problem. I would love to hear from anyone if there is any problem with this method.
Kotlin
If you still want to use a delay (or not)
Handler(Looper.getMainLooper()).postDelayed({
// Your Code
}, 1000)
Put Code Where Are getting error and doing any network operations
new Handler().post(new Runnable() {
#Override
public void run() {
// add your code here
}
});
I think you can create a main handler instance in your activity and override handle message method. you can save a handler quote in your work thread.When you finished work you can use handler to send a message and you receive message in handle message method. To start animation from handler message method and so on...

What is the correct way to implement this do while?

I start my GUI like this, which seems correct.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame gui = new JFrame();
gui.setExtendedState(JFrame.MAXIMIZED_BOTH);
gui.setVisible(true);
}
});
At a certain point in the application, the playTurn() method gets fired. The for loops all turns in the list.
for (String turn : controller.getTurns()) {
playTurn(turn);
}
I now load the correct panel with my CardLayout which worked fine. Then I had to write the playTurn() method. So playTurn() gets called. It should do certain things according to some variables. But it should not return until some buttons are disabled. This is what I can't achieve, the program just stops working. I can guess it's in the direction of threads etc.. but can't seem to figure it out. Thanks in advance.
public void playTurn(String turn) {
if (controller.givePlayers().contains(turn)) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
while (!turnFinished) {
if (!button1.isEnabled() && !button1.isEnabled() && !button1.isEnabled() && !button1.isEnabled()) {
turnFinished = true;
}
}
}
});
} else {
deletePlayer(turn);
}
}
Sorry for bad formatting. Couldn't find where.
EDIT:
The GUI stops being responsive. Can't close program either.
I tried using a SwingWorker for the while which does not block the GUI but still playTurn() returns.
I have even tried creating a new thread where I call the method. The doesn't get blocked anymore but the method still returns.
Thread one = new Thread() {
public void run() {
playTurn(turn);
}
};
FIXED: Placing the runnable up higher in the stack;
Your playTurn method runs the code on the EDT, cause of this line javax.swing.SwingUtilities.invokeLater(new Runnable() {, which makes your application GUI unresponsive as GUI-changing code must generally be run on the EDT. Since your buttons won't change from your GUI, once the loop starts, it might just loop forever.
By running the code in another Thread, you won't freeze your GUI. I'm guessing, since you don't provide much informations on the rest of your code, that you might have to change the way you handle things once your loop is done.
Edit from comments : Since you don't want playTurn to return, don't use a thread within it and make sure playTurn is not running on the EDT. Your playTurn method will return after creating and making a new Thread run the code.
You might want to try dong it like this :
Runnable code = new Runnable() {
#Override
public void run() {
for (String turn : controller.getTurns()) {
playTurn(turn);
}
}
};
if (!SwingUtilities.isEventDispatchThread()) {
code.run();
} else {
new Thread(code).start();
}
To make sure you don't run the code on the EDT. That way, playTurn doesn't return until the loop condition is met, the GUI stays responsive.
public void playTurn(String turn) {
if (controller.givePlayers().contains(turn)) {
while (!turnFinished) {
if (!button1.isEnabled() && !button1.isEnabled() && !button1.isEnabled() && !button1.isEnabled()) {
turnFinished = true;
}
}
} else {
deletePlayer(turn);
}
}
Doing this might have you change a few things more.
The idea is to make the call to a new Thread where you don't want it/need it to wait for the code being run in a new Thread to end to continue.

Get error exception when using the sleep function

I want to delay my application for a while while a melody is playing, and when it's finished change the image on an imageview.
public void addListenerOnButtons() {
harmonicaTecknad= (ImageView)this.findViewById(R.id.harmonicatecknadspelautblas);
harmonicaTecknad.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknadtryckrood);
RunAnimations();
utblas=MediaPlayer.create(SpelaTonerActivity.this, R.raw.utblas4);
utblas.start();
Thread timer = new Thread(){
public void run() {
try { // The delay should occur here
sleep(utblas.getDuration());
} catch(InterruptedException e) {
e.printStackTrace();
} finally {
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknad1);
}
}
};
timer.start();
}
}
I get an exception error, obviously I cannot set the image inside the thread, so where should I set it?
This is all explained in details, with examples, in the android documentation:
Android offers several ways to access the UI thread from other
threads. You may already be familiar with some of them but here is a
comprehensive list:
Activity.runOnUiThread(Runnable)
View.post(Runnable)
View.postDelayed(Runnable, long)
Handler
[...]
Unfortunately, these classes and methods could also tend to make your
code more complicated and more difficult to read. It becomes even
worse when your implement complex operations that require frequent UI
updates.
To remedy this problem, Android 1.5 and later platforms offer a
utility class called AsyncTask, that simplifies the creation of
long-running tasks that need to communicate with the user interface.
Write harmonicaTecknad.setImageResource(R.drawable.harmonicatecknad1); code on UI thread because you can not write UI code to non UI thread.
So simply replace above line of code with
runOnUiThread(new Runnable()
{
#Override
public void run()
{
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknad1);
}
});
If you are still getting error then for testing purpose just change sleep(utblas.getDuration()); with sleep(1000);
As the other answers say, you need to set the image from the UI thread. However, while you can use Thread.sleep(), you should in general avoid using sleeps for logic. Most classes have some way to get callbacks when things happen - for example in your case you can use MediaPlayer.OnCompletionListener. You register for a callback from the media player, and that callback will always be on the UI thread. This is what it looks like:
public void addListenerOnButtons() {
harmonicaTecknad= (ImageView)this.findViewById(R.id.harmonicatecknadspelautblas);
harmonicaTecknad.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknadtryckrood);
RunAnimations();
utblas=MediaPlayer.create(SpelaTonerActivity.this, R.raw.utblas4);
utblas.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
harmonicaTecknad.setImageResource(R.drawable.harmonicatecknad1);
}
};
utblas.start();
}
}

Categories

Resources