'JavaFX thread should wait for background thread but without freezing the UI (JavaFX)
I want my main thread to wait until the background thread completes. But, this makes my UI freeze. I want to achieve this without freezing my UI. Please help me out. I am new to JavaFX.
My Code is ---
waitNotifyClass wait1 = new waitNotifyClass();
private void download(ActionEvent event) throws SQLException, IOException, InterruptedException {
try (Connection conn = ......getConnection()) {
/// opening filechooser
FileChooser fc = new FileChooser();
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("Compressed(zipped) Folder (*.zip)", "*.zip");//Compressed(zipped) Folder (*.gz)", "*.gz"
fc.getExtensionFilters().add(extFilter);
String downloadsLocation = System.getProperty("user.home") + "/Downloads/";
/// get a File file with name as you save in file chooser
file = fc.showSaveDialog(downloadMultiTraceFileButton.getScene().getWindow());
file.mkdirs();
File sourceFile = file;
String s = file.getAbsolutePath().substring(0, file.getAbsolutePath().length() - 4);
destFile = new File(s);
if (sourceFile.renameTo(destFile)) {
System.out.println("File renamed successfully");
} else {
System.out.println("Failed to rename file");
}
/// object of the folder made after renaming
File theDir = new File(destFile.getAbsolutePath());
/// Iterating through the slected item of trace files one by one for create a file and then fill it
Task task = new Task() {
@Override
protected Void call() throws Exception {
for (String str : traceFileListView.getSelectionModel().getSelectedItems()) {
File myFile = new File(theDir.getAbsolutePath() + "\\" + str);
/// make new file if myFile doesnt exist
if (!myFile.exists()) {
myFile.createNewFile();
}
/// get writer object of FileWriter for writing finally on file from
FileWriter writer = new FileWriter(myFile);
/// query for getting content of trace file
String querySubPart = "select * from table_name='" + str + "'";
PreparedStatement preparedStatement = conn.prepareStatement(querySubPart);
ResultSet resultSet = preparedStatement.executeQuery();
resultSet.setFetchSize(200);
/// writing into file from resultSet
System.out.println("writing before while loop " + Thread.currentThread());
while (resultSet.next()) {
try {
writer.write(resultSet.getString(1));
System.out.println(resultSet.getString(1));
} catch (IOException ex) {
System.out.println("inside try of write");
}
}
writer.close();
}
wait1.notifyFunction();
updateProgress(1, 1);
return null;
}
};
System.err.println("Thread created" + Thread.currentThread());
new Thread(task).start();
wait1.waitFunction();
//// closing the window open where download button was there
((Stage) generateTraceFileButton.getScene().getWindow()).close();
/// getting sourcepath folder which is to be zipped
String sourcePath = theDir.getAbsolutePath();
// name of zip folder
String destinationpath = theDir + ".zip";
System.out.println(destinationpath);
packInZipCode(sourcePath, destinationpath);
} catch (SQLException e) {
System.out.println("Exception caught \n" + e.toString());
if (e.toString().trim().toUpperCase().contains("----")) {
....
}
}
}
I am sure that my UI is freezing because of wait1.waitFunction()
because this is making my UI thread wait and freeze the UI. I want to wait for it but without freezing the app.
Edited--
why do I want to achieve this?
because If I will not stop my UI thread, it will go ahead and zip my file. but that same file is being used by the background thread also. So I won't get the desired output. Also, my main task is to do the downloading part(here it is heavy, so take time) in the background thread. At the same time, I don't want my main thread to freeze.
I tried this--->
Implemented task.setOnSucceded just after thread creation so that my JavaFx thread will execute this part only after task is completed.
But in this case , background thread(task is executing here) is losing connection .
Got this error-->
java.sql.SQLException: Connection is closed
at this line-->
preparedStatement = conn.prepareStatement(querySubPart);
My new Code looks like this -->
private void downloadMultiTraceFiles(ActionEvent event) throws SQLException, IOException, InterruptedException {
try (Connection conn = mainApp.getHikariDataSource().getConnection()) {
/// opening filechooser
FileChooser fc = new FileChooser();
FileChooser.ExtensionFilter extFilter = new FileChooser.ExtensionFilter("Compressed(zipped) Folder (*.zip)", "*.zip");//Compressed(zipped) Folder (*.gz)", "*.gz"
fc.getExtensionFilters().add(extFilter);
String downloadsLocation = System.getProperty("user.home") + "/Downloads/";
/// get a File file with name as you save in file chooser
System.out.println("Inside runlator" + Thread.currentThread());
file = fc.showSaveDialog(downloadMultiTraceFileButton.getScene().getWindow());
System.out.println("Path of file->" + file.getAbsolutePath());
file.mkdirs();
File sourceFile = file;
String s = file.getAbsolutePath().substring(0, file.getAbsolutePath().length() - 4);
destFile = new File(s);
if (sourceFile.renameTo(destFile)) {
System.out.println("File renamed successfully" + Thread.currentThread());
} else {
System.out.println("Failed to rename file");
}
/// object of the folder made after renaming
File theDir = new File(destFile.getAbsolutePath());
/// Iterating through the slected item of trace files one by one for create a file and then fill it
Task task = new Task() {
@Override
protected Void call() throws Exception {
for (String str : traceFileListView.getSelectionModel().getSelectedItems()) {
System.out.println("inside of the for loop " + Thread.currentThread());
File myFile = new File(theDir.getAbsolutePath() + "\\" + str);
/// make new file if myFile doesnt exist
if (!myFile.exists()) {
myFile.createNewFile();
}
/// get writer object of FileWriter for writing finally on file from
System.out.println("t1--------- " + Thread.currentThread());
FileWriter writer = new FileWriter(myFile);
System.out.println("t2----------- " + Thread.currentThread());
/// query for getting content of trace file
String querySubPart = "select payload from gv$diag_trace_file_contents where trace_filename='" + str + "'";
System.out.println("t3----------- " + Thread.currentThread());
PreparedStatement preparedStatement = conn.prepareStatement(querySubPart);
System.out.println("t4----------- " + Thread.currentThread());
ResultSet resultSet = preparedStatement.executeQuery();
resultSet.setFetchSize(200);
/// writing into file from resultSet
System.out.println("writing before while loop " + Thread.currentThread());
while (resultSet.next()) {
try {
writer.write(resultSet.getString(1));
System.out.println(resultSet.getString(1));
} catch (IOException ex) {
System.out.println("inside try of write");
}
}
writer.close();
}
wait1.notifyFunction();
updateProgress(1, 1);
return null;
}
};
System.err.println("Thread created" + Thread.currentThread());
new Thread(task).start();
wait1.waitFunction();
task.setOnSucceeded((e) -> {
System.out.println("Inside set on succeeded"+Thread.currentThread());
//// closing the window open where download button was there
((Stage) generateTraceFileButton.getScene().getWindow()).close();
/// getting sourcepath folder which is to be zipped
System.out.println("before zip");
String sourcePath = theDir.getAbsolutePath();
// name of zip folder
String destinationpath = theDir + ".zip";
System.out.println(destinationpath);
try {
packInZipCode(sourcePath, destinationpath);
} catch (IOException ex) {
Logger.getLogger(GenerateTraceFilesController.class.getName()).log(Level.SEVERE, null, ex);
}
});
} catch (SQLException e) {
System.out.println("Exception caught \n" + e.toString());
if (e.toString().trim().toUpperCase().contains("ORA-48127")) {
....
}
}
}
Solution 1:[1]
If you want your main thread to wait, and at the same time you don't want your UI to be frozen, then you can use:
task.setOnSucceeded(e->{'your code'})
For example:
Thread t1 = new Thread(task);
t1.start();
Thread.interrupted();
task.setOnSucceeded(e -> {
System.out.println("inside succeeded");
String sourcePath = theDir.getAbsolutePath();
// name of zip folder
String destinationpath = theDir + ".zip";
System.out.println(destinationpath);
try {
//// calling the function where zipping code is written
packInZipCode(sourcePath, destinationpath);
} catch (IOException ex) {
Logger.getLogger(GenerateTraceFilesController.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("zip sucessfully ---" + Thread.currentThread());
// for deleting the folder from which our zip folder made, bcs it is duplicate now, so dlete it
deleteDirectoryLegacyIO(theDir);
System.out.println("end succeeded");
});
This part of the code will be run by the JavaFX thread. and your UI will also not freeze. This solved my problem.
Why do you want to run those codes by the Javafx thread?
because some works /operations can be done only by the JavaFX thread. These works include Filechooser, file operations, label setting, etc. So you can't run these in your background thread, so we want to run them by the Main thread.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | jewelsea |