I want to make a thread, that loads data from the file. I was thinking of using the invokeLater() method. But I think I messed up somewhere and can't figure out where.
This is my thread:
public class LoadBooks extends Thread{
private ArrayList<Book> books;
@Override
public void run() {
try
{
FileInputStream fis = new FileInputStream("SaveBooks.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
books = (ArrayList<Book>) ois.readObject();
fis.close();
ois.close();
}catch(Exception e)
{
}
}
public ArrayList<Book> getBook() {
return books;
}
}
I am using thread like this:
if(e.getSource() == loadBookButton){
LoadBooks loadBooks = new LoadBooks();
loadBooks.start();
EventQueue.invokeLater(() -> books = loadBooks.getBook());
EventQueue.invokeLater(() -> updateUI(books));
}
How I think that should work: Books will be loaded from the file in another thread. When books are loaded, I will get them from my thread and then I will update my GUI.
What is the problem?: GUI is not updating, because ArrayList books
is empty. So there is a problem somewhere. I think that maybe I do not understand fully, how the invokeLater works. I was looking up in java docs but didn't get much help.
Suppose you are going to make a meal, but you've come to a step where you need flour, and when you look in the pantry there is none. So, you ask your friend who was busy working in the garden to stop what they're doing and run out to buy some flour. Then, the very moment your friend steps out the door, you try to proceed with making the recipe, but What the ???? There's no flour! How can there be no flour when I just sent him out the door to get some?
You're going to have to wait for the flour.
Your program is trying to do the same thing. It's trying to use the books when it's only just sent the LoadBooks
thread out to fetch them. You're going to need some way for the LoadBooks thread to signal when the books have been loaded, and you need some way for the GUI thread to wait until the signal is delivered.
A Semaphore
would be good for that. The LoadBooks thread could call semaphore.release()
to signal that the books have been loaded, and the GUI thread could call semaphore.acquire()
to await the signal.
But Wait!!
Is there something else you could be doing in the kitchen while your friend is shopping for flour? If there is not—if you are not going to do anything at all except sit there and wait—then you might just as well have gone for the flour yourself and not interrupted your friend's work.
There is practically never any reason for some thread A to give a task to some other thread B if thread A is going to do nothing but wait until the task is finished. It that's all you want to do, then you might as well just do the task in thread A.
It's tricker with a GUI, because maybe you are trying to prevent the GUI from "freezing up" while the books are being loaded. The thing is, in that case, if the GUI doesn't freeze up, what does it do instead?
The simplest answer to that question is to have the GUI put up a modal dialog box that says something like, "loading books," and not show any controls that let the user do anything else until the books are loaded. Maybe if you're nice, you'll show a progress bar in the dialog to show them how long they will have to wait. Maybe if you are really nice, you could even give them an "abort" button to quit out of the program if they decide not to wait.
Unfortunately, I can't say much about how to do those things. I've never been much of a GUI programmer, and it's been maybe a decade since I did any in Java.