I am trying to run android.animation.ValueAnimator from a separate thread from the UI thread. As I understand it, ValueAnimator can only be ran from the UI thread. Is there a proper way to start it from another thread to run on the UIThread?
I wrapped the ValueAnimator in an other class which holds a switch for the UI thread to periodically check.
private ArrayList<Animation> animators;
public void onResume(){
while(true)
{
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
checkAnimations();
}
}
public void checkAnimations()
{
for(Animation va: animators)
{
if(va.animationHasStarted())
va.actuallyStartTheAnimation();
}
}
public void RegisterAnimation(Animation valueAnimator)
{
animators.add(valueAnimator);
}
The infinite loop causes the UI to stall. Do you know of a better implementation/design pattern.
Related
my program's UI freezes for some time after pressing a JButton. I discovered that a cause of this is a Semaphore clogging the Swing thread. This is the method containing the acquire() call on the Semaphore:
private void fetch(int numThreads) {
//some code here
sem = new Semaphore(numThreads);
for (int i = 0; i < model.getRowCount(); i++){
try {
sem.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
//some code here
}
And here is the only method that makes a call to fetch()
concFetchButt.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
switchButtonStates(false);
}
});
fetch(Integer.parseInt(threadsNumField.getText()));
}
As I understand, this code ends up running fetch() on the Swing thread, though, supposedly it has nothing to do with Swing.
I guess, my question is this: How do I run a method called from 'ActionPerformed()' of Swing on the main thread of the program instead of the Swing thread?
No need to specifically run that on the "main" thread. Simply run it on any other thread but the Swing UI thread.
The most simple solution to get there:
add an ExecutorService to your class
put that code fetch(Integer.parseInt(threadsNumField.getText())); into a Runnable object
Submit that Runnable to the ExecutorService
Along the lines of:
private final ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
public void run() {
fetch(Integer.parseInt(threadsNumField.getText()));
}
});
I'm trying to make an JavaFX application that tracks the movement of my mouse for this im using this code in the controller class:
new Thread(new Runnable() {
#Override public void run() {
while (Main.running) {
Platform.runLater(new Runnable() {
#Override
public void run() {
try {
label.setText(MouseInfo.getPointerInfo().getLocation().toString());
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
}
}).start();
But it couses my application to lag big time.
How should i fix this lag problem?
Thanks i fixed it:
new Thread(new Runnable() {
#Override public void run() {
while (Main.running) {
Platform.runLater(new Runnable() {
#Override
public void run() {
label.setText(MouseInfo.getPointerInfo().getLocation().toString());
}
});
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
What you doing is letting Javafx Application thread Thread.sleep(1000); <-wait
Any long term action you shoud put OUT of JFX-AT. And only update your ui components on it.
new Thread(()->{
while(Main.running){
Platform.runLater(()->{
//updateui component
//this is updating on FXAT
});
Thread.sleep(time)//This way you dont let JFXAT wait
}
}).start();
//Not sure if formatted and curly braces correctly.Bud you hopefully understand.Make sure you know which thread you let wait.Otherwise you wont be able to recieve events from paused jfxat.
You should put your Thread.sleep() call in your while loop and not in your Runnable, otherwise the loop keeps posting a lot of runLater tasks and those tasks stops the event thread for 1000ms after updating your mouse position
You call Thread.sleep(long) inside a Runnable that will be executed on the UI thread. If the thread is sleeping, it can't do anything else but sleep there. If you want your label to update every 1000 milliseconds, you can use the java.util.Timer class to make that happen.
I am attempting to make an application that retrieves images and .mp3 files and transitions from one image to the next once the audio has finished. The underlying framework of how I transition between these images is a little convoluted, but I have managed to get an action in SWT that successfully enables me to manually transition from one to the next. However, a problem has arisen when I've tried to automate it; when placed into a loop, my playAudio() method begins before all of the calls I make in my displayShow() method have resolved, which results in a blank window, despite the audio still playing.
Here is the run method for the action that I want to start the show:
Action startAction = new Action("Start") {
public void run() {
//do {
displayShow();
playAudio();
//} while(true);
}
};
Here is playAudio(). I am able to PLAY the audio without incident:
public void playAudio() {
final String audio = "Happy_Birthday.mp3";
audioLatch = new CountDownLatch(1);
audioThread = new Thread() {
public void run() {
try {
Player player = new Player
(new BufferedInputStream
(new FileInputStream(audio)));
player.play();
audioLatch.countDown();
} catch (JavaLayerException e) {
} catch (FileNotFoundException e) {
} catch (Exception e) {
}
}
};
audioThread.start();
try {
audioLatch.await();
} catch (InterruptedException e) {
}
}
And here is displayShow():
private void displayShow() {
new Thread() {
public void run() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
Control[] children = container.getChildren();
for (int i = 0; i < children.length; i++) {
children[i].dispose();
}
show.showSlide(container);
container.layout();
}
});
}
}.start();
}
show.showSlide returns a composite whose parent is container, which is the immediate child of the highest parent composite. Within the newly created composite, an image is added to a label and the label's parent is assigned to composite. I realize whether displayShow() is in a separate thread or not seems to be immaterial; this was just the last thing I tried.
It is not solely the addition of the loop that causes the refresh to not execute. The only way I can get the manual transition to work is if I remove the CountDownLatch from the playAudio() method. Were I to remove this latch, the only way to encase these two methods in a loop would be embedded while loops, which seem to hog a fair amount of the CPU and still does not solve my problem. Am I missing anything?
The audioLatch.await() is blocking the main program thread, this is the thread that all SWT operations run on so the Display.asyncExec runnables are just being queued until the thread is available.
If you really must wait in the playAudio method you could run the display event loop there until the background thread is finished:
while (! background thread finished)
{
if (!display.readAndDispatch())
display.sleep();
}
I am trying to run a background service as part of my GUI application. I am using an ExecutorService and I am getting a Future back from it. This code shows what I am doing:
play.addActionListener( new ActionListener() {
service.submit(new Runnable(){ .... } }
}
Now, the submission is happening on the GUI thread, which should propagate exceptions to the main thread. Now, I don't want to block the main thread on future.get, but I would rather have some way of checking for the result of the future, so that the exceptions are proapagated to the main thread. Any ideas?
You could use a listener pattern to be notified when the background thread is done. SwingWorker for instance allows for PropertyChangeListeners to listen to the SwingWorker.State state property and you could either do this or roll your own. This is one of my favorite features of a SwingWorker.
An example....
final MySwingWorker mySwingWorker = new MySwingWorker(webPageText);
mySwingWorker.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getNewValue().equals(SwingWorker.StateValue.DONE)) {
try {
mySwingWorker.get();
} catch (InterruptedException e) {
e.printStackTrace(); // this needs to be improved
} catch (ExecutionException e) {
e.printStackTrace(); // this needs to be improved
}
}
}
});
mySwingWorker.execute();
You can check Future.isDone() to see if it has finished, or you can have the background task perform the action e.g.
play.addActionListener( new ActionListener() {
service.submit(new Runnable(){
public void run() {
try {
// ....
} catch(Exception e) {
SwingUtils.invokeLater(new Runnable() {
public void run() {
handleException(e);
}
}
}
}
});
You could have an additional thread just to monitor the state of the future:
final Future<?> future = service.submit(...);
new Thread(new Runnable() {
public void run() {
try {
future.get();
} catch (ExecutionException e) {
runOnFutureException(e.getCause());
}
}
}).start();
And somewhere else:
public void runOnFutureException(Exception e) {
System.out.println("future returned an exception");
}
I would like to get a recurring call back to invalidate a view. I am sure there is a neat way to do this. I am currently doing this and would like a neater / better solution if possible?
new Thread()
{
#Override
public void run()
{
while (!Thread.currentThread().isInterrupted())
{
handler.post(new Runnable()
{
public void run()
{
BannerButton.this.invalidate();
}
});
try
{
Thread.sleep(50); // yields 20 fps
} catch (InterruptedException e)
{
Thread.currentThread().interrupt();
}
}
}
}.start();
For a single shot timer on the UI thread, I do this: (But I cant find a way to do this with repeats)
(new Handler()).postDelayed(new Runnable()
{
#Override
public void run()
{
// Do stuff
}
}, SPLASH_SHOW_TIME);
Timer looked good, but it calls on a background thread.
Thanks.
Your second try using Handler is already correct. Just store the Handler and the Runnable in a field, and then inside the run() method (possibly at the end), call again
handler.postDelayed(runnable, 1000);
Look at the View.postInvalidate() method. This is different from invalidate() as you can do it from any Thread you want. It just posts an invalidate() message in the UI thread Looper
Concerning your second question simply post with some delay the same Runnable at the end of the Runnable in your Handler