Concurrency 持续更新文本区域
我正在编写一个程序,使用youtube dl创建一个进程。该进程有两个Concurrency 持续更新文本区域,concurrency,javafx,textarea,task,Concurrency,Javafx,Textarea,Task,我正在编写一个程序,使用youtube dl创建一个进程。该进程有两个InputStreams(InputStream和errorStream),我想将其中的每一个重新路由到一个文本区域 我一直试图在不锁定JavaFX线程的情况下更新TextAreas。它正在工作,但我觉得它非常低效,因为它创建了大量只附加一行的任务对象。我重新创建了我在下面使用的代码,使用List而不是BufferedReader来简化问题 当我按下按钮时,它将创建两个线程,每个列表一个,带有UpdateTask。然后,Upd
InputStream
s(InputStream和errorStream),我想将其中的每一个重新路由到一个文本区域
我一直试图在不锁定JavaFX线程的情况下更新TextArea
s。它正在工作,但我觉得它非常低效,因为它创建了大量只附加一行的任务对象。我重新创建了我在下面使用的代码,使用List
而不是BufferedReader
来简化问题
当我按下按钮时,它将创建两个线程,每个列表一个,带有UpdateTask
。然后,UpdateTask创建一个WriteTask
并将其交给Platform.runLater()
,然后将其再次放在JavaFX线程上
肯定有更好的办法吗
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
public class ConcurrentTest extends VBox{
TextArea output;
TextArea error;
Button start;
TextField writable;
public ConcurrentTest(){
// Init components
output = new TextArea();
output.setEditable(false);
error = new TextArea();
error.setEditable(false);
// Init button
start = new Button("Print stuff");
start.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
List<String> outputLines = Arrays.asList("A", "B", "C", "D");
List<String> errorLines = Arrays.asList("A", "B", "C", "D");;
Thread outputThread = new Thread(new UpdateTask<String>(output, outputLines));
outputThread.setDaemon(true);
outputThread.start();
Thread errorThread = new Thread(new UpdateTask<String>(error, errorLines));
errorThread.setDaemon(true);
errorThread.start();
}
});
writable = new TextField();
writable.setPromptText("Write while some text areas are getting updated.");
// Add components
this.getChildren().addAll(output, error, start, writable);
}
// UPDATE TASK CLASS
public class UpdateTask<V> extends Task<V>{
TextArea target;
Iterator<String> it;
public UpdateTask(TextArea target, List<String> lines){
this.target = target;
it = lines.iterator();
}
@Override
protected V call() throws Exception {
while(it.hasNext()){
Thread.sleep(1500); // Time to type something to test
Platform.runLater(new WriteTask<String>(target, it.next()));
}
return null;
}
}
// WRITE TASK CLASS
public class WriteTask<V> extends Task<V>{
TextArea target;
String line;
public WriteTask(TextArea target, String line) {
this.target = target;
this.line = line;
}
@Override
protected V call() throws Exception {
target.appendText(line + "\n");
return null;
}
}
}
这里的解决方案应该是100%相同的:
Task
s相对较轻;您只想避免创建许多线程。您只需在每次单击按钮时创建一个新线程,这应该很好。如果你看到性能问题,你可以考虑创建一个单一的,并提交<代码> UpDestTebug < /代码> s;但是我不认为这里会有问题。@James_D我以为用大量的任务调用Platform.runLater()
效率会很低,我会继续使用这个系统。谢谢你的评论!每1.5秒节流一次,这样就可以了。如果您反复调用Platform.runLater(…)
,而不阻塞,您将淹没FX应用程序线程并使UI无响应,但(据我所知)您在这里没有这样做。@James\D每秒调用15次会不会太多?因此,在我的示例中,我有两个线程,每个线程进行15次runLater()
调用,每秒总共进行30次调用。我如何检查性能?我不太熟悉多线程。
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class ConcurrentTestLauncher extends Application {
@Override
public void start(Stage primaryStage) {
try {
Parent root = new ConcurrentTest();
Scene scene = new Scene(root);
primaryStage.setTitle("Concurrent FX Test");
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}