alright so let's take a look at how we can work with background threads in the
UI applications now with the javafx section of this course we took a look at
the javafx.concurrent package when working with threads in a UI
application this is the go-to package to use when we want to perform a background
task we use a class that implements the worker interface or a class that extends
the task class let's take a look at extending the task class now the task
class implements the runnable interface and we can use task objects whenever or
wherever we use runnable objects so let's start by creating a new javafx
project so i'm gonna click on create new project going to select
javafx next and let's call this one task example and get that started so
what we're going to do here is we're going to simulate fetching data from a
database on a background thread which is a common situation in a UI application
another example would be fetching data from the internet so we'll get that data
on a background thread using a task so the first thing we need to do then is
create an anonymous task object we need to access the task within the controller
so if the simplicity we're going to create it in the controller java
file
let's go ahead and do that and we've got that open as you can see there and what
we'll do is set up and will need a need to add a method in this class called
initialize and we need to create the task within that if you recall the
initialize method is run whenever the controller instance is created we went
through that in detail in the javafx section
alright so let's get started....
and if some of this is not making sense or you want to know more about
javafx do go back and check out the javafx section it might actually be
worthwhile to go back and look at that and before going through this examples
particularly if something its not making sense
so we are defining our task first and let's create our public void initialize method
which is used by javafx to initialize and then want to initialize a task a
task.....and you can see by doing that I managed to get it to create
a lot of this code for us come down here and put a semicolon to make it
valid to close the statement off and the idea there is that when creating a
class that extends task we have to override the call method and that's
obviously I did their now let's suppose that we are fetching a list of employee names so
we're going to return the list as an observable list of strings you can see
that we got the return type defined in their the call method and so we've specified
that return type and declaring the task variable so obviously when we got
IntelliJ to generate the code for us it knew based on what I've typed in here
under the Declaration of tasks that it need to return that observable list of string
objects
alright so inside the call method we need to perform the background task
itself so we're going to put some code in there i'm going to delete this null
return null statement first I'm going to get it to sleep so...
...then we'll just return...
....and what I'll do is type some names...
....so I'll pretend
database query is going to return six records and as you saw on line 15 we have
introduced a sleep for one second and that's simulating simulating the
database fetch and we need to make sure that any of our imports or the javafx
varieties in other words if you're getting any errors here most likely its
because the javafx wasn't used in the import so do check your import lines
if you are getting errors now notice that we are throwing exception from the call
method here on line 14 now we do so because the thread.sleep method can
actually throw and interrupted exception now rather than using a try-catch block
we just throwing the exception from the method to keep the example code simple
but in a real world application you'd probably want catch that
error and do something with it
alright so next we need to start this thread from the user interface now in the
sample.fxml file that comes with all the javafx projects we need to add a
button its going to start the task when that button is pressed lets just go and open
it up and grab that file or at least open it so we can work on it...
and we'll add the button so within the grid pane
we're going to do a....
...that will be the method that
is executed and its in red because we haven't written it yet and....
....
....so next we need to add this action listener that
we just defined here on line 8 into our controller going to add
this down here underneath the initialize method
its going to be....
we need to annotate that as we need to do for FXML.....and if
you go back and look at our sample now notice that that's now change color
because it's now linked it to this code here and in terms of what we're going to
do to process this what actually need to take after the button is clicked
we're going to do a new thread and task
and we defined
the task on line 10 and then we've actually put what's going to happen what's gonna
happen in terms of functionality in our task when we defined that in the
initialize method we're going to pass or do a new thread task.start to
start the thread
alright so let's actually just run this alright so I just press the get employee names
button now looks like nothing happened but in fact the task did run but we need
to show the employee named in the user interface but recall that we can only
access UI controls on the main thread the javafx applications thread that is
because the controls themselves aren't thread-safe now rather than making them
thread-safe javafx enforces the rule that all code that touches the user
interface must run on the javafx application thread that way threads
can't interfere with each other when they're updating or when updating the UI
component so how do we update the UI with the results of a task we ran on
a background thread
well it's actually a couple of ways to we can do this let's go back we're going
to close down the program first let's go back to our fxml file just close down the
run window so let's add a list view which will display the list of
employee names so below the button it's going to be....
....
......we need to reference the listview in the controller so i'm
going to set its fx ID...we are going to set that equal to listview so
that we can update that and reference that as I mentioned in code so let's just run this
to make sure that we can see the listview first okay i can expand the window
if we need to expand the window to make it larger you can see we can clearly see
the listview there so that's good well close it down so we have to increase the
height and the length of the window to see the entire listview as you saw me do now we
could increase the height when we create this scene but i'll leave that as an
exercise for you to look at later since we've worked on code similar to that in
the javafx section in any event since there's only six items we won't need to
increase the height very much to see them all anyway
alright so going back to the controller we need to define the listview we are going
define it up here below the task we've implemented on line we've defined on line
10 and the do....making sure the names are the same
and I'll import that making sure that i select the javafx.seen and not
the javafx.swing and we need to annotate that and fxml make sure that
that's valid and it links correctly so now that we've done that we can update the
list view by using the platform.run later method now this method accepts
runnable accept a runnable and runs it on the UI thread now our task is a
runnable but we don't want to run our task on the UI thread we want to update
the list view when the tasks complete will call run later when the task wakes
up from sleeping will have to create our observable list earlier rather than the
return statement so that we can use it to set the listview let's change the
code a little bit here instead of doing a return there
we're going to do observable list....
...
and what we had defined their previously then after that we're going to do is do
a platform.....like so and you can see that IntelliJ
helpfully added the extra code for us and the code that we want to run it will
be listview....but also what I need to do is put a
return.....because we've gotta some data that needs to be returned so
put that in there
alright so let's run this and see whether it works I'm just gonna expand
this in preparation and click on get employee names you can see that there
was a delay their over a second then the listview got updated so you might be
wondering why we're returning the list from the task this is the line that i
added just before we ran it on line 38 since we're updating the list view from
the task we don't have to return the list when we use performed.runlater
to update the UI but we do need to return it for the second way that
we can update the UI from a task so while we can use platform.runlater to
update the UI it's not good practice to tie a task to the UI in this way if we
have a change the UI would also have to change the task so in general the UI
code and the code that processes data should be kept separate so there's a
better way to update the list view and this is the recommended way to do it
so instead of using platform.run later we can use what's called data
binding so the task class is a property called value which is the value returned
by the task in our example it would be the observable list of strings the list
view control has a property called items and that contains the items that the
list view is displaying what we're going to do is bind the items property in the
tasks value property whatever the value property changes the items property will
update
accordingly we no longer have to explicitly update the list view by
calling platform.runlater so lets give that a go so I'm just going to close
this down the run window again so basically all this code here remains the
same right until the end of the Declaration what we then do is remove
this platform.runlater so we're going to be doing that anymore and then below
afterward we defined the task we do.....
we're going to bind task.value property as you can see so after
declaring the task we bind the list views items property to the tasks value
property can see that on line 34 so lets run the codes to check that it
works you can see there was a pause there after a while and then it did
actually work we saw that the employee names appear in the list view so great
so we're performing a long-running task on a background thread and updating the
task on the UI thread better yet the task doesn't know anything about the UI
all it's doing is returning a list of names and it doesn't actually care what
happens to it after that
so a list can be written to a file display it on the screen printed to the console
or used for something else
it actually doesn't matter to the task code and it's not tied to the UI now in
any way so we can do other things with tasks such as passing parameters to them
and executing code when they completed if you're interested you can what
you can do with tasks you can read more about the task documentation here i'm
just going to quickly bring that up in a browser
so there's a link which will be in the resources section so you can find out a
lot more information at that link if you so desire
alright so the application is working fine but we're going to actually look at
enchaining this in the next video
let's just imagine that it takes 10 seconds to fetch a large group of
records from a slow database would be great to have a progress bar so that we
can see that something's working in that the updates happening
let's look at implementing that in the next video