2014-07-04 55 views
1

使用我的控制器类,我必须执行多个IO命令(例如:具有某些参数值的SSH,RCP命令)顺序方式。每个命令都会得到一些时间来执行。如何以顺序方式执行javaFX任务,服务

当每个命令开始执行时,我必须更新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立刻)。但由于自然或并发性,我无法以顺序方式(并非全部一次,一个接一个地)在任务或服务的帮助下执行这些命令。我该如何解决这个问题。提前致谢。

+3

看看顺序执行示例:[如何重置JavaFX2中任务之间的进度指示器?](http://stackoverflow.com/questions/16368793/how-to-reset-progress-指示器之间的任务功能于javafx2) – jewelsea

回答

1

我想在项目中的确切要求,它可以完成任务和服务。你只需要一个正确的实现。
注意事项:
1.始终使用service或Platform.runLater启动后台任务。
2.如果要更新UI,必须从任务或服务完成。
3.将任务的进度属性绑定到进度条的进度条,以便平滑更新。
4.同样将Label的文本属性绑定到任务的消息属性,以平滑更新状态或其他内容。

要执行外部命令状外壳等我写了下面的类:

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项目及其广义的&精简版项目。
希望这有助于