【问题标题】:How to execute javaFX Tasks, Services in sequential manner如何按顺序执行 javaFX 任务、服务
【发布时间】:2014-07-04 07:50:48
【问题描述】:

使用我的 Controller 类,我必须以顺序方式执行几个 IO 命令(例如:SSH、带有一些参数值的 RCP 命令)。这个命令中的每一个都会得到一些时间来执行。

当每个命令开始执行时,我必须更新 UI 控制器。 然后根据该执行结果(无论是成功还是失败),我必须再次更新 UI。 然后必须以相同的步骤执行下一个命令。

每个命令的执行取决于前一个命令的结果。例如,

for (IOCommand command : commandsList) {

    // Update the UI before start the command execution  
    messageTextArea.append("Command " + command.getType() + " Stated");

    boolean result = commandExecutor(command);  

    if(result) {

      // Update the UI after successful execution  
      messageTextArea.append("Command " + command.getType() + " Successfully Executed");

      // Then go to next command execution 

    } else {

      // Update the UI after failure execution  
      messageTextArea.append("Command " + command.getType() + " Failed");

      // Fix the issue and do re execution
      commandReExecutor(command);       
    }
} 

为了完成这个逐步的 UI 更新,我必须使用一些与 JavaFX 相关的任务或服务相关的功能(否则它会挂起应用程序,直到完成所有命令的执行,并且它会一次更新 UI)。但是由于性质或并发性,我无法在任务或服务的帮助下以顺序方式执行这些命令(不是一次全部,一个接一个)。我该如何解决这个问题。提前致谢。

【问题讨论】:

标签: java javafx sequential


【解决方案1】:

我有一个项目中的确切要求,它可以通过任务和服务来完成。你只需要一个正确的实现。
几点注意事项:
1. 始终使用 service 或 Platform.runLater 启动后台任务。
2. 如果要更新 UI,必须从 Task 或 Service 中完成。
3. 将任务的进度属性绑定到进度条的属性,以便顺利更新。
4. 类似地将标签的文本属性绑定到任务的消息属性,以便顺利更新状态或其他内容。

要执行 shell 等外部命令,我编写了以下类:

package utils;

import controller.ProgressController;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.concurrent.Task;
import main.Installer;

public class ProcessExecutor extends Task<Integer>
{
    Logger logger =Logger.getLogger("ProcessExecutor");
    File dir;
   String []cmd;
    String cmds;
    int exitCode=-1;
    boolean NextStepExists=false;
    Task nextStep;
    public ProcessExecutor(String...cmd )
{
    this.cmd=cmd;
    this.dir=new File(System.getProperty("user.dir"));
    this.nextStep=null;
    NextStepExists=false;
}
public ProcessExecutor(Task nextStep,String...cmd )
{
    this.cmd=cmd;
    this.dir=new File(System.getProperty("user.dir"));
    this.nextStep=nextStep;
    NextStepExists=true;
}
public ProcessExecutor(Task nextStep,File dir,String...cmd)
{
    this.cmd=cmd;
    this.dir=dir;
    this.nextStep=nextStep;
    NextStepExists=true;
}


@Override
protected final Integer call()
{
    cmds=new String();
        for(String i:cmd)
            cmds+=i+" "; // just to log cmd array

    try
    {

        logger.info("Starting new process with cmd > "+cmds);

        ProcessBuilder processBuilder=new ProcessBuilder(cmd);
        processBuilder.directory(dir);
        processBuilder.redirectErrorStream(true);
        Map<String, String> env = processBuilder.environment();
        // create custom environment 
        env.put("JAVA_HOME", "/opt/jdk1.7.0_45/"); 

        Process pr=processBuilder.start();
        BufferedReader in = new BufferedReader(new InputStreamReader(pr.getInputStream()));
           String line = in.readLine();
            while (line != null) {
                logger.log(Level.FINE,line);
                ProgressController.instance.printToConsole(line);
                line = in.readLine();
            }
            BufferedReader er = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
           String erLine = in.readLine();
            while (erLine != null) {
                logger.log(Level.FINE,erLine);
                ProgressController.instance.printToConsole(erLine);
                erLine = in.readLine();
            }


        exitCode=pr.waitFor();
        exitCode=pr.exitValue();
        logger.info("Exit Value="+exitCode);
        updateMessage("Completed Process");
        if(exitCode!=0 && exitCode!=1)
        {
            logger.info("Failed to execute process commands >"+cmds+" with exit code="+exitCode);
            failed();
        }

        else
        {
            logger.info("PE succeeded()");
            if(NextStepExists)
                Installer.pool.submit(nextStep);
            succeeded();
        }

    }
    catch(Exception e)
    {
        logger.log(Level.SEVERE,"Exception: Failed to execute process commands >"+cmds,e);
        updateMessage(e.getMessage());
    }

    return new Integer(exitCode);



}
@Override
public void failed()
{
    super.failed();
    logger.log(Level.SEVERE,"Failed to execute process commands >"+cmds+"; ExitCode="+exitCode);

}
}



该类使用 ProcessBuilder 为新进程创建所需的环境,
它使用 process.waitFor() 等待完成进程的执行,
可以使用 processBuilder.directory(dir) 设置进程的目录。

为了随时执行单个任务 ,使用 java.util.concurrent.ExecutorService

public ExecutorService pool=Executors.newSingleThreadExecutor();
pool.submit(new ProcessExecutor("installTomcat.bat","tomcat7"));
pool.submit(new ProcessExecutor("installPostgres.bat","postgresql","5432"));


这样你可以一个接一个地执行批处理文件。
Executors.newSingleThreadExecutor() 负责随时执行单个任务并将新提交的任务排队。

我写了一个通用的工作此处的顺序执行示例:
github
这是一个 NetBeans JavaFX 项目,它是项目的通用和精简版本。
希望这会有所帮助

【讨论】:

    猜你喜欢
    • 2018-12-31
    • 1970-01-01
    • 2019-12-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多