in the previous video we saw how the application we developed could end up in
the you know showing a bad user experience and again that's because the
event handlers code that we write runs on the UI thread and just a note in here
that there is going to be a future section of the course that deals with
its concept of threads in detail for now just think of it as a process that sort
of runs by itself on the computer but we'll be talking about that a lot more
in detail but basically the event handler which is still running on the UI
thread isn't the optimal solution for process that takes some time to complete
in other words if our event handlers needs to do something that it will take more than let's
say a second then what it should really be doing is starting another thread now this
new thread would do the work that's gonna take a while to process so the event handler
which is still running on the UI thread will be able to return and the UI thread
can listen to a user input again so from a perspective of the user who is
running the application they won't see the pauses and the delays and the weird
things that are happening in the last video when our application was waiting for
something to happen so we refer to the thread that's going to do the work that
will take awhile as the background thread as opposed to the UI thread now when the
background thread is completed the work it notify the user interface so for
example if the event handler needed to retrieve data from a data base well you
know perhaps the internet what it would do is kick off this background thread to do
the data retrieval and when the background thread has the data and it's completed
what it needs to do it will inform the UI and then the data can then be loaded into
the user interface so I know that sounded a bit complex but lets code an example
of how we go about this so instead of putting the UI thread to sleep as we did
previously what we can do is we gonna kick off a background thread and put
that to sleep and when it wakes back up we are gonna notify the user interface we are
gonna update a controller on the screen to say that process is actually completed so what
we need to do to start this working is to add a label control to a our grid pane and
lets go and do that first and we want to add that below the check box so down here
we are gonna add the label.....
....
..so that's gonna be our notification that
something's working so lets swim back over to our controller class and lets
actually add the fxml annotation first....
....so you can add the @fxml
annotation before you actually done the declaration that's quite acceptable and we need to
accept that label which making sure its a java fx control which it is so that's
good what we need to do is going to go to our button class code because you
still want the code to be executed or invoke from here but we don't worry want
to run in here so what we need to do is to do something a bit different and
we are going to create a runnable called task that will ultimately going to
contain the code that we want to run in the background thread and again in
terms of runnables and threads and so forth there is a section or will be a
section in the Java course detailing this so you don't really need to
understand you know in intricate detail what we are talking about with threads so
long as your understanding that is basically just a process that's working
on your computer somewhere so let's go ahead and do that so we are gonna changes this code
where we had this try and catch we are gonna change that a little bit and we are going to
actually make that create a runnable....we are gonna press enter
their and when I do that you should find it will generate some code for us I'm just gonna
press enter and notice when I did that it created all that code for us so that's
the something else that IntelliJ would do for you automatically and this
process is going to actually do the work of setting up and running this
code in the background so its no longer gonna be running on a UI thread its gonna
create another process virtually another program another instance of something
running in the background on your computer to do whatever processing we want
and in this case the only processing we do want is to run that thread.sleep....
so.....and actually what I should have done
probably better to copy this code and I just pasted it in there because its
identical code the differences is were putting this in a runnable so that is
actually running in the background thread so everything is the same as it was before other
than the fact that its in a runnable and the other thing you need to do to make
this valid we need to put a semi colon at the end of that runnable line their and that's now set up our task and you can see this automatically
a method that was created in there when I created the runnable task and that's
telling the background process what it has to do so you put your code you want executed
within in that run method so we want to obtain our label when the thread wakes up
so we are gonna set the text to our label right after thread.sleep returns so the code
is gonna sit there and not do anything and when it's finished after
that ten seconds then we want to update our label so we can see that it's actually updated so...
...and we should be able to see that
on the screen so at the moment we've now got our
runnable task we've sort of declared what needs to happen we've said that it's
going to be sit their and pause for 10 seconds after 10 seconds it's gonna
update our label on the screen but what we haven't done yet is invoked it because
what we need to do is actually start it so it actually start the process just like
declaring a variable declaring it is one step but using its another one so we need to
actually start using it so to actually start this we need to come over here and
underneath the declaration we type....
...and that's the code to start that now so not only
have we defined we've now put the code in to actually
run it so what we going to do now is we're gonna run this and we should
be able to see that it will run and our UI should still be responsive and after 10
seconds have elapsed we should be able to see it automatically update the
screen so lets run this now so now that we're putting the background thread to
sleep and not the UI thread the UI shouldn't freeze for 10 seconds when we
press a button so we should still be able to press the buttons and see our message printed on
the console you know right away and our label will update when the background threads
finished running or basically pausing for 10 seconds or sleeping for 10 seconds
every time we press a button our event handle will kick off another background thread but
we'll only see our label update once and that's because every background thread
will say the same text so you won't know which background thread has
updated the label because the same content each time so we got this running on
the screen now so lets see if it actually works as we expected to so type Tim in
the text field press the say hello button and now I'm gonna click on say bye so that's good that's
working so lets wait until our label updates and watch that on the screen and oops we
actually got an error so the label in fact didn't update instead if we have a
look at our stack trace our error you can see that the exception there is the legal
state exception not on ethics application thread and just a number
there which may be different for you in this case is current thread equals thread five
so what's going on here what does that actually mean well it turns out that the
scene graph isn't thread-safe in other words the code assumes that nodes in the
screen graph will only ever be updated by the same thread mainly the UI thread
and which we've learned is also known as the JavaFX application thread so if more
than one thread could update the node it would be possible for the internal
integrity of the node to be compromised if you think about it so for example
with thread a runs and starts to change the state of a node and then it suspended
so that thread b can run nothing in the JavaFX code prevents thread b from also
updating the same node
so in other words thread b could wipe out what thread a started so
there'd be some sort of compromise these two processes on the computer running at
the same time and that is sort of conflicting with each other so basically thread
b could wipe out what thread a has started as I mentioned and when thread a runs again it
continues its updates not knowing that its previous updates were overwritten by
thread b so you can see how the internal state or integrity of a node
could be compromised in that situation now because of that the developers of JavaFX
well you know keenly aware that this is being a problem and so whenever we want to work with nodes
on the scene graph we actually must do so on the JavaFX application thread now if we
don't in other words if we try to update something as I have done here that's not in the UI thread
then we are going to actually get an exception like this one which was caused
was the IllegalStateException and again in our code we are trying to update the label you can see
that on line 41and that's a node obviously in the scene graph from the background thread
that's what why we are actually getting the error now this incidentally an improvement over
swing which was Java's old UI took kit the same restriction existed there but
the runtime didn't throw an exception so in other words it just let us go ahead and
do the update and weird bugs weren't actually resolved so although this is an
error at least JavaFX is actually stopping us from doing it knowing that down the tract their would be
getting all sorts of problems with your code anyway but enough about the theory
how do we actually fix this well when we're doing a long task on a background thread
you usually want to update a part of the UI when the tasks finish so what we
really need here is a way to force code to run on the UI thread and JavaFX
actually provides us with a way to do this and we are going to use the run later
method in the platform class and the run later method actually accept a
runnable parameter and again runnables is an interface that we've actually used already on line 36 and its basically
an interface that classes implement when their instances will be executed on a
thread as we saw with our code there and also the developer doesn't want the
class to inherit from the Thread class so the platform.runlater methods
is gonna put the runnable parameter that's passed
onto the UI threads queue so in other words it's gonna force the runnable objects
to run on the UI thread and in this process that's exactly what we want to
do so in the run method itself that we've defined on line
38 of our background thread we are gonna use platform.runlater to update the label and when
the long-running task if the background thread has finished executing in other
words were not gonna put this first runnable using platform.runlater but
because we got the same issues and in fact its effectively gonna be running on the
UI thread it's only after we've finish our processing sort of as the last line we
execute in the run method that we are gonna do this extra bit of code so lets actually closed it down and try it
so basically instead of trying to put update our label right here on line 42 instead what we are
going to do is put....
...
.....
...so basically what we're doing here is we're actually pausing still
for 10 seconds as you can see there on line 41 but then after that we are
basically invoking the command so that the actual label is gonna be
updated on the UI thread so we don't get any exception so its a little bit more code but essentially that's the
way that the JavaFX developers want us to actually update things so lets try running
this again now we should find it actually works
so we got our code running so type Tim and click on say hello and I should now be able to click on say bye say hello clear say hello
that's all working nicely types something else in and lets just wait a bit longer and you
can see the screen then update we did something so it actually worked this
time so our thread quite happily paused for 10 seconds while I was doing other
things and you notice that the user interface was quite responsive during that time
we didn't have any slowdowns or pauses
or weird things happening it was all running like you would have expected to do so
now their is fx application thread method is a useful method in the platform class and it
returns true when the code is running on the JavaFX application thread
and false otherwise and you can actually use that method when we try to debug our code because
we're not getting the exception anymore and we're not really sure which thread of
code block is running on so let's actually add this code just us to see how you go about
doing that so come down here now to we are actually in now in our button click code again the code up here that actually
creates the runnable this is actually within the run methods so creates the run
later with the new runnable so within their I'm gonna put...
....
.....
....
...
..so let's
actually checked that and see our output when we run that and put something in there
....and click on say hello you can see it says I'm going to sleep on the background thread which is what
we expect so now we need to just wait until that returns which we will get a notification
that its on the UI thread there it is I am updating the label on the UI thread so
that's a very useful way to debug code because we are not getting any exception because
it's working correctly if you want to try and figure out where your code is
being executed and basically using
platform.runlater is one way to ensure the code runs on the UI thread and JavaFX
also provides a set of a APIs that helped us run background threads and
also to communicate with the UI and the APIs are in the JavaFx.concurrent
package and this isn't really much more advanced topics that we are not going to cover here now we may look
at that when we get to the concurrency threads in a separate section so if
you're interested in learning more about it too can actually read the
documentation on that bring that up on the screen
you can go to the link their concurrency.htm in the oracle documentation and you can actually read more about that in their
links is actually in the Resources section as well
ok so at this point now we've learned the fundamentals of how to build a
JavaFX application so its time to put it all together and what we gonna do is
build an application that actually does something meaningful so we are gonna start doing
that in the next lecture