I'm trying to periodically update a Google Maps marker in FXML. I tried to do this with a Timer and a new Thread, but can't get any of it to work.
I tested the new Thread with the simple task to update a TextField in my UI, which works just fine.
However, when I use the actual code that I need to update the map:
#FXML
public void handleTracking() throws IOException, InterruptedException {
new Thread() {
#Override
public void run() {
while (true) {
try {
double ar[] = FileImport.getGpsPosition();
System.out.println("Latitude: " + ar[0] + " Longitude: " + ar[1]);
double Ltd = ar[0];
double Lng = ar[1];
webEngine.executeScript(""
+ "window.lat = " + Ltd + ";"
+ "window.lon = " + Lng + ";"
+ "document.goToLocation(window.lat, window.lon);");
try {
Thread.sleep(555);
} catch (InterruptedException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
} catch (IOException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}.start();
}
I get the Output message:
Exception in thread "Thread-26" java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-26
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:236)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:423)
at javafx.scene.web.WebEngine.checkThread(WebEngine.java:1216)
at javafx.scene.web.WebEngine.executeScript(WebEngine.java:980)
at de.fkfs.v2x.eval.FXMLDocumentController$1.run(FXMLDocumentController.java:84=)
A similar thing happens when I use a Timer, it works for the task of updating a label, however if I try to update the marker position it throws the message:
Exception in thread "Timer-0" java.lang.IllegalStateException: Not on FX application thread; currentThread = Timer-0
Updates to the UI, including calls to webEngine.executeScript(...) must be executed on the FX Application thread.
On the other hand, the FX Application Thread is (effectively) the thread used for rendering the UI and processing user input. So if you block this thread with an infinite loop, or other long running process, or if you schedule too many things to run on that thread, you will make the UI unresponsive.
What you are trying to do in your code appears to be to update the UI as fast as you can. If you put the loop in the FX Application Thread you will block it entirely: if you put it on a background thread and schedule the updates using Platform.runLater(...) you will flood the FX Application Thread with too many updates and prevent it from doing its usual work, and it will become unresponsive.
The general solution here revolves around the fact that it's really redundant to update the UI so often. The human eye can only detect visible changes at a limited rate, and in technology terms you are limited by, e.g. the refresh rate of the physical screen and of the underlying graphical software. JavaFX attempts to update the UI at no more than 60Hz (in the current implementation). So there's really no point in updating more often than the underlying JavaFX toolkit updates the scene.
The AnimationTimer provides a handle method that is guaranteed to be invoked once per scene update, no matter how frequently that occurs. AnimationTimer.handle(...) is invoked on the FX Application Thread, so you can safely make changes to the UI here. So you could implement your tracking with:
private AnimationTimer tracker ;
public void initialize() {
tracker = new AnimationTimer() {
#Override
public void handle(long timestamp) {
try {
double ar[] = FileImport.getGpsPosition();
// System.out.println("Latitude: " + ar[0] + " Longitude: " + ar[1]);
double Ltd = ar[0];
double Lng = ar[1];
webEngine.executeScript(""
+ "window.lat = " + Ltd + ";"
+ "window.lon = " + Lng + ";"
+ "document.goToLocation(window.lat, window.lon);");
} catch (IOException ex) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
}
};
}
#FXML
public void handleTracking() {
tracker.start();
}
The only thing to be wary of here is that, because handle() is invoked on the FX Application Thread, you should not perform any long-running code here. It looks as though your FileImport.getGpsPosition() method performs some IO operations, so it should probably be delegated to a background thread. The trick here, which is the one used by JavaFX classes such as Task, is to continually update a value from a background thread, and only schedule a call to Platform.runLater(...) if one is not already pending.
First, just define a simple class for representing the location (make it immutable so it is thread-safe):
class Location {
private final double longitude ;
private final double latitude ;
public Location(double longitude, double latitude) {
this.longitude = longitude ;
this.latitude = latitude ;
}
public double getLongitude() {
return longitude ;
}
public double getLatitude() {
return latitude ;
}
}
and now:
#FXML
private void handleTracking() {
AtomicReference<Location> location = new AtomicReference<>(null);
Thread thread = new Thread(() -> {
try {
while (true) {
double[] ar[] = FileImport.getGpsPosition();
Location loc = new Location(ar[0], ar[1]);
if (location.getAndSet(loc) == null) {
Platform.runLater(() -> {
Location updateLoc = location.getAndSet(null);
webEngine.executeScript(""
+ "window.lat = " + updateLoc.getLatitude() + ";"
+ "window.lon = " + updateLoc.getLongitude() + ";"
+ "document.goToLocation(window.lat, window.lon);");
});
}
}
} catch (IOException exc) {
Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.SEVERE, null, ex);
}
});
thread.setDaemon(true);
thread.start();
}
The way this works is that it creates a (thread-safe) holder for the current location, and updates it as fast as possible. When it updates it, it (atomically) also checks if the current value is null. If it's null, it schedules a UI update via Platform.runLater(). If not, it simply updates the value but schedules no new UI update.
The UI update (atomically) gets the current (i.e. most recent) value and sets it to null, indicating it is ready to receive a new UI update. It then processes the new update.
This way you "throttle" the UI updates so that new ones are only scheduled when the current one is being processed, avoiding flooding the UI thread with too many requests.
All JavaFX UI elements must be updated inside the FX application thread!
If using an additional thread be sure to use platform.Runlater() to update your UI elements!
Related
I'm using a thread to periodically run a three second background animation.
I adapted the code in question from a Thread Demo example written in Swing and used
it to replace a not quite working earlier version that used both a thread and a task.
My program stops/suspends the thread when either playing a video or running an animation
and starts a new thread when ending the video or animation. This seems to work without
any downside which is why I'm puzzled why my earlier JavaFX searches hadn't turned up
a similar solution to the one I'm using. It seems a rather direct approach for running
short, simple background animations.
Where am I going wrong with this? What am I missing? How would I rewrite this code
using both a Thread and a Task or do I need to?
I should add - the while and run statements are virtually unchanged from the original
and the only significant addition to the Swing code was to add thread.setDaemon( true )
to startThread().
A podcast listener.
// background thread
class BackGround extends Thread {
#Override
public void run() {
while ( suspend.getValue() == false ) {
try {
int r = shared.randInt( 5, 10 );
Thread.sleep( r * 1000 );
} catch ( InterruptedException e ) {
// do nothing
}
if ( suspend.getValue() == false ) {
Platform.runLater( () -> {
int g = shared.cssGradients.length - 1;
g = shared.randInt( 0, g );
gradientColor.set( shared.cssGradients[g] );
Boolean bif = shared.updatePanes( shared.cssGradients[g],
leftPane, rightPane );
});
}
}
}
} // class background
// start thread
public synchronized void startThread() {
thread = new BackGround(); // Thread thread ...defined elsewhere
thread.setDaemon( true );
thread.start();
}
// stop thread
public synchronized void stopThread() {
suspend.set( true );
}
The reason the Task class is useful for JavaFX is that it provides a number of callbacks like succeeded(), failed() or cancelled() and methods like updateProgress() and updateMessage() that will run in the JavaFX Application thread and therefore let you update the UI without Platform.runLater( () -> { ... }); This makes the Task class a perfect choice for doing background tasks like downloading data or long running computations.
However, since your thread simply runs continuously without ever really finishing its work, it doesn't seem that you would need any of the additional functionality a Task would provide you with over a simple Thread.
Still, if you really wanted to convert your code to use a Task, it would look just like this:
class BackGround extends Task<Void> {
#Override
protected Void call() throws Exception {
while (suspend.getValue() == false) {
try {
int r = shared.randInt(5, 10);
Thread.sleep(r * 1000);
} catch (InterruptedException e) {
// do nothing
}
if (suspend.getValue() == false) {
Platform.runLater(() -> {
int g = shared.cssGradients.length - 1;
g = shared.randInt(0, g);
gradientColor.set(shared.cssGradients[g]);
Boolean bif = shared.updatePanes(shared.cssGradients[g],
leftPane, rightPane);
});
}
}
return null;
}
}
// start thread
public synchronized void startThread() {
Task<Void> bg = new BackGround();
Thread taskThread = new Thread(bg);
taskThread.setDaemon(true);
taskThread.start();
}
// stop thread
public synchronized void stopThread() {
suspend.set( true );
}
As you see, it really doesn't make a difference for you, as you don't need anything that a Thread couldn't give you. If however you wanted to have closer communication with the UI thread, e.g. showing a progress bar or showing status updates, then a Task would give you the tools to do that.
I guess its also worth mentioning that the use of a Timeline would be quite elegant for triggering your animations. It would look somewhat like this:
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
int g = shared.cssGradients.length - 1;
g = shared.randInt(0, g);
gradientColor.set(shared.cssGradients[g]);
Boolean bif = shared.updatePanes(shared.cssGradients[g], leftPane, rightPane);
}
}
));
timeline.setCycleCount(Animation.INDEFINITE);
timeline.play();
The code inside the handle() method is run every second in the JavaFX Application thread. Unfortunately this only lets you set a fixed time between executions, while you seem to want to wait a random amount of time each time.
TL;DR: Using a Thread is ok, because you don't need the additional functionalities of a Task in your use case.
I am struggling with using Clipboard from a console application. The error handler would return the following error.
"Current thread must be set to single thread apartment (STA) mode before OLE calls can be made"
I set the STA attribute to the main function and that worked well when calling from main. However, I need to cyclically call that function and in this case I get back that error.
I'm trying to figure out how to use an own thread in my funtion. Now, it just works once but in the 2nd call from my timer, I am not able to reach the area of the code after where I created the thread
public string getRawData()
{
string sChatRawTxt = string.Empty;
try
{
// copy data to clipboard using an Autoit script
Process.Start("copyChatToClipboard.au3");
System.Threading.Thread.Sleep(500);
Thread staThread = new Thread(x =>
{
if (Clipboard.ContainsText())
{
sChatRawTxt = Clipboard.GetText();
Clipboard.Clear();
}
});
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
staThread.Join();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
return sChatRawTxt;
}
This is the timer from where my function is called. If I set a breakpoint to separateComments, it only works one time, then I am no longer able to reach that position. Do I have to somehow close the thread from before?
public void OnTimedEvent_scannerCyclic(object source, ElapsedEventArgs e)
{
string sRawTxt = getRawData();
// then separate/ remove the useless data
string sComments = SeparateComments(sRawTxt);
}
[STAThread]
public static void Main(string[] args)
{
stdTimer = new System.Timers.Timer(1000);
stdTimer.Elapsed += new ElapsedEventHandler(this.OnTimedEvent_scannerCyclic);
stdTimer.Enabled = true;
while (true)
{
// main program
//System.Threading.Thread.Sleep(1000);
}
}
thanks a lot for help
So the only solution i figured was to use my own timer that i implemented in the main as below
TimeSpan deltaT = TimeSpan.FromMilliseconds(1000);
DateTime timeLastCall = DateTime.Now;
while (true)
{
// main program
DateTime currentTime = DateTime.Now;
if(currentTime - timeLastCall > deltaT)
{
Scanner.mainCyclicCall();
timeLastCall = currentTime;
}
System.Threading.Thread.Sleep(100);
}
I dont have a lot of c# experience, it is actually my first little project. I dont know if there is a better way to cyclically access Clipboard in a console application. Also using a dispatcher timer did not work out, I read console apps dont have a dispather.
I'm trying to do some optimization in my code and would like to spawn a thread where I do a time consuming operation. During the implementation of that optimization I was running into an issue which was driving me crazy. I simplified the issue and created a test case for that specific issue: (I'm using SpringJUnit4ClassRunner so the transaction is properly started at the beginning of the testCRUD method)
Could someone help me understand why the foundParent is null in the thread ?
private Semaphore sema = new Semaphore(0, false);
private long parentId;
#Test
public void testCRUD() {
//create
DBParent parent = null;
{
parent = new DBParent();
parentDao.persist(parent);
parentId = parent.getId();
assertTrue(parentId > 0);
parentDao.flush();
}
(new Thread(
new Runnable() {
public void run()
{
System.out.println("Start adding childs !");
DBParent foundParent = parentDao.findById(parentId);
assertTrue(foundParent != null); //ASSERTION FAILS HERE !!!!
System.out.println("Releasing semaphore !");
sema.release();
System.out.println("End adding childs !");
}
})).start();
try {
System.out.println("Acquiring semaphore !");
sema.acquire();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
=============================EDITED===================================
As per one comment suggestion, I created a threadManager bean which spawn the thread. Here is the code of the threadManager:
public class ThreadManager {
#Transactional(propagation=Propagation.REQUIRES_NEW)
public void executeTask(String Name, Runnable task) {
(new Thread(task, Name)).start();
}
}
Then in the previous test, instead of staring the thread manually, I just post it in the thread manager like this:
#Autowired private ParentDao parentDao;
#Autowired private ThreadManager threadManager;
private Semaphore sema = new Semaphore(0, false);
private long parentId;
#Test
public void testCRUD() {
//create
DBParent parent = null;
{
parent = new DBParent();
parentDao.persist(parent);
parentId = parent.getId();
assertTrue(parentId > 0);
parentDao.flush();
}
threadManager.executeTask("BG processing...",
new Runnable() {
public void run()
{
System.out.println("Start adding childs !");
DBParent foundParent = parentDao.findById(parentId);
assertTrue(foundParent != null); //ASSERTION FAILS HERE !!!!
System.out.println("Releasing semaphore !");
sema.release();
System.out.println("End adding childs !");
}
});
try {
System.out.println("Acquiring semaphore !");
sema.acquire();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
Unfortunately this doesn't work either !!! :-(
The transaction context is bound to the thread. So the code in the spawned thread doesn't run in the same transaction context as the code in the initial thread. So, due to transaction isolation (the I in ACID), the spawned thread doesn't see what the initial thread's transaction is inserting in the database.
You can bind Spring transaction to a new thread, to run transactions & Hibernate/JPA access in it. But this has to be a different TX and JPA/HB session from other threads.
Spring code for OpenSessionInViewFilter, is a reasonable an example of how to bind Hibernate session to Spring's TX management. You can strip this down to fairly minimal code.
See:
org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
OpenSessionInViewFilter.doFilterInternal() -- this is where it actually binds it
TransactionSynchronizationManager.bindResource()
TransactionSynchronizationManager.unbindResource()
TransactionSynchronizationManager.getResource()
In one project (IIRC) I wrapped this functionality into a 'ServerThreadHb' class, to setup & save previous thread-bindings on construction -- with a restore() method to be called in a finally block, to restore previous bindings.
For your posted code sample, there isn't much point in running work on a separate thread -- since you synchronously wait for the work to be done. However I assume you were planning to remove that constraint & extend that functionality.
I am looking for a way to display images on my ListField from a background thread. First in my drawListRow i try this
path = (String) imagePaths.elementAt(index);
bit = connectServerForImage(path);
g.drawBitmap(xText, y + yText, 80, 200, bit, 0, 0);
but can't scroll smoothly throughout the list, and they say do not do networking or other blocking operations on the UI. But i also try this
private class imgConnection extends Thread
{
public imgConnection() {
super();
}
public void run() {
try {
for (int i = 0; i < imagePaths.size(); i++)
{
final int index = i;
String path = imagePaths.elementAt(index).toString();
bit = connectServerForImage(path);
image.addElement(bit);
}
}
catch (Exception e)
{
System.out.println(e.toString());
}
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
_list.setSize(image.size());
subManager.add(_list);
screen.invalidate();
}
});
}
}
public void drawListRow(ListField list, Graphics g, int index, int y, int w) {
bit = (Bitmap) image.elementAt(index);
g.drawBitmap(xText, y + yText, 80, 200, bit, 0, 0);
}
but nothing happens. Any idea, comments.
You are right, i just started java development 2 weeks ago particularly BB development and i try this link. I want to add a background thread to download image after i got the path url from json return.
first thread:
_connectionthread = new Connection();
_connectionthread.start();
private class Connection extends Thread
{
public Connection()
{
super();
}
public void run() {
try {}
catch (Exception e) {}
}
}
second thread:
_imgConnectionThread = new ImgConnection();
_imgConnectionThread.start();
private class ImgConnection extends Thread
{
public ImgConnection() {
super();
}
public void run() {
try {
}
catch (Exception e)
{
}
}
}
how to update images on ListField?
Answer is based on code from - pastebin.com/90UKTHzP
Terrible code! It's really hard to read and undersand! It looks like you copy pasted several examples from different locations. Also you overriding default behavior with same behavior. Also MainScreen already has VerticalManagerField. Also you're adding list every iteration to manager which will cause IAE. And main one thread is depended on result of second one. They start at the same time, but getting json from server and it's processing could take longer time, so image thread most probably will finish his run without any result.
So main recommendation to fix it - read clean code book! Read more about java development - conventions, multithreading. Read about BB development - UI api, networking.
And finally - start only one thread to get and parse json. After you get it finished - start another thread to get images.
There some minor things that could save you more battery and processor time also - start loading images on demand - when it painted or going to be painted (user scrolls list).
By convention, Java class names start with a capital letter, so imgConnection should really be ImgConnection.
In your sample code, I don't see imgConnection being instantiated anywhere, and I don't see any call to Thread.start(), which is the way a thread i started. Without Thread.start() it is not surprising nothing is happening - the thread is never starting.
I'm developing a database application for Windows Phone 7.5 (mango). I trying (during tapping on a button) to update a textblock with the text "Searching..." This button performs a rather lengthy search in a big table and thus I want to inform the user. However everything I trying is failed! Here is one of the code snippets that I used. Is there any way to achieve this? Any help helping me understand what's wrong would be appreciated.
private void btnSearch_Tap(object sender, GestureEventArgs e)
{
workerThread = new Thread(new ThreadStart(turnVisibilityOn));
workerThread.Start();
while (!workerThread.IsAlive) ;
Thread.Sleep(500);
//Search database takes about 15 sec on windows phone device!
Procedures[] results = CSDatabase.RunQuery<Procedures>(#"select Code, Description from tblLibraries where Description like '%" +
textBox1.Text + "%' or Code like '%" + textBox1.Text + "%'");
this.MyListBox.ItemsSource = results;
// Of course this not work
Search1.Text = ""
}
private void turnVisibilityOn()
{
// Inform the user updating the Search1 textblock
// UIThread is a static class -Dispatcher.BeginInvoke(action)-
UIThread.Invoke(() => Search1.Text = "Searching...");
}
public static class UIThread
{
private static readonly Dispatcher Dispatcher;
static UIThread()
{
// Store a reference to the current Dispatcher once per application
Dispatcher = Deployment.Current.Dispatcher;
}
/// <summary>
/// Invokes the given action on the UI thread - if the current thread is the UI thread this will just invoke the action directly on
/// the current thread so it can be safely called without the calling method being aware of which thread it is on.
/// </summary>
public static void Invoke(Action action)
{
if (Dispatcher.CheckAccess())
action.Invoke();
else
Dispatcher.BeginInvoke(action);
}
}
I am not sure I understand the problem correctly.
The "Searching..." text does not show up? The
// Of course this not work
Search1.Text = ""
line doesn't work? (Why do you write "Of course this not work"? Why wouldn't it work?)
I don't understand why you change the text to "Searching..." in a background thread. You could do it in the UI thread, and make the time-consuming work in the background thread, something like this (I switched to using a ThreadPool):
private void btnSearch_Tap( object sender, GestureEventArgs e )
{
Search1.Text = "Searching..."
ThreadPool.QueueUserWorkItem(p =>
{
Procedures[] results = CSDatabase.RunQuery<Procedures>( #"select Code, Description from tblLibraries where Description like '%" +
textBox1.Text + "%' or Code like '%" + textBox1.Text + "%'" );
// Dispatch manipulation of UI elements:
Dispatcher.BeginInvoke( () =>
{
this.MyListBox.ItemsSource = results;
Search1.Text = "";
} );
} ) ;
}
You always have to manipulate the UI elements from the UI thread (on which the event handler runs) and you have to do the time-consuming work in a background thread.