繁体   English   中英

在Java中执行过程而不会冻结JFrame

[英]Execute process in Java without JFrame freezing

在不冻结程序的情况下如何在Java中执行进程? 我已经尝试过使用SwingWorker,但是我还不太了解它是如何工作的。

我还有其他方法可以做到这一点吗? 我想在我的JDroidLib中使用类似的东西。 有关完整的源代码,请查看GitHub: http : //github.com/Team-M4gkBeatz/JDroidLib

提前致谢!

编辑:

感谢您的回答。 但是我有一个带有几种方法的类(嗯,它不止一个类,但是我明白了)。 如何使用SwingWorker与之交互?

这是类之一:

/**
 *
 * @author Simon
 */
    public abstract class Command extends SwingWorker {

    BufferedReader prReader = null;
    ProcessBuilder process = null;
    Process pr = null;
    Date timeNow = new Date();
    String osName = System.getProperty("os.name");

    public void executeProcessNoReturn(String _process, String arg) throws IOException {
        process = new ProcessBuilder(_process, arg);
        pr = process.start();
    }

     public String executeProcessReturnLastLine(String _process, String arg) throws IOException {
        process = new ProcessBuilder(_process, arg);
        pr = process.start();
        prReader = new BufferedReader(new InputStreamReader(pr.getInputStream()));
        String line;
        while ((line = prReader.readLine()) != null) {
            // Wait for input to end.
        }
        return line;
    }

    public StringBuilder executeProcessReturnAllOutput(String _process, String arg) throws IOException {
        process = new ProcessBuilder(_process, arg);
        pr = process.start();
        prReader = new BufferedReader(new InputStreamReader(pr.getInputStream()));
        StringBuilder output = null;
        String line;
        while ((line = prReader.readLine()) != null) {
            output.append(line);
        }
        return output;
    }

    public boolean isProcessRunning(String processName) throws IOException {
        boolean value = false;
        if (osName.equals("Linux") | osName.contains("Mac")) {
            process = new ProcessBuilder("ps", "-e");
            pr = process.start();
            String line;
            prReader = new BufferedReader(new InputStreamReader(pr.getInputStream()));
            while ((line = prReader.readLine()) != null) {
                if (line.contains(processName)) { value = true; break; }
            }
        } else {
            String winDir = System.getenv("windir") + "/System32/tasklist.exe";
            process = new ProcessBuilder(winDir);
            pr = process.start();
            String line;
            prReader = new BufferedReader(new InputStreamReader(pr.getInputStream()));
            while ((line = prReader.readLine()) != null) {
            if (line.contains(processName)) { value = true; break; }
            }
        }

        return value;

    }

     public String executeProcessReturnError(String processName, String arg) throws IOException {
        process = new ProcessBuilder(processName, arg);
        process.redirectError();
        pr = process.start();
        prReader = new BufferedReader(new InputStreamReader(pr.getErrorStream()));
        String line;
        String output = "";
        while ((line = prReader.readLine()) != null) {
        output += line + "\n";
        }
        return output;
    }
}

是的,您可以使用SwingWorker其想法是,一个任务需要花费大量时间在单独的线程(后台线程)中运行,因此您不会阻塞gui,并且JFrame不会冻结。 这是一个完整的示例,我非常喜欢Swing Worker示例

基本上作为示例,您将创建自己的扩展SwingWorker的类重写doInBackground

注意:您可以具有类似普通班级的字段。

范例:

class Worker extends SwingWorker<Void, String> {
    private SomeClass businessDelegate;    
    private JLabel label;

    @Override
    protected Void doInBackground() throws Exception {
       //here you make heavy task this is running in another thread not in EDT
        businessDelegate.callSomeService();
        setProgress(30); // this is if you want to use with a progressBar
        businessDelegate.saveToSomeDataBase();
        publish("Processes where saved");
        return null;
    }

    @Override
    protected void process(List<String> chunks){
       //this is executed in EDT you can update a label for example
       label.setText(chunks.toString());
    }

   //add setters for label and businessDelegate    
}

您还阅读了有关process(..) publish(..)done()

并在您的客户端代码中放入。

SwingWorker<Void,String> myWorker = new Worker();
myWorker.execute();

您需要在单独的Thread中运行代码。 用于在程序中运行和协调多个代码路径的关键字是“并发”:

http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html

多线程代码可能会变得非常棘手且难以调试,但是Java提供了一些更高级别的抽象/概念,使使用多线程代码的出错率降低了。

看一下这些概念的java.util.concurrent包。

由于使用AWT / Swing时必然会遇到多线程问题,因此有一些实用程序类/方法专门设计用于在图形应用程序中促进多线程处理。 SwingWorker是其中之一(另一个是例如SwingUtilities.invokeLater() )。 熟悉它们是一个好主意,它们可以使您的生活更轻松,尤其是对于那些足以使GUI冻结的简单任务。

如果使用的是Swing,则可以使用SwingWorker

既然您提到您不了解它是如何工作的,我将给出一个简单的解释。

Swing事件处理代码在事件分发线程中完成 因此,如果用户单击一个按钮(例如,从服务器获取数据并在窗口中显示数据的更新按钮),则在事件分发线程中将调用该按钮的ActionListener。

如果在同一线程中获取数据,则UI将冻结,因为UI无法处理任何事件(您正在事件分发线程中运行代码)。

因此,您应该在单独的线程中获取数据。 但是,在获取数据之后,应将其设置为事件分发线程中的视图。

Swing工作人员为您简化了这一工作。 您将繁重的任务放入doInBackground方法中(在本例中为获取数据),并从该方法返回繁重任务的输出(在本例中为数据)。

在swing worker的done方法中,调用get方法,该方法将为您提供doInBackground方法中返回的数据。 在那里,您使用新数据更新视图(例如,将数据添加到TableModel中)。

现在,当您在swing工作者上调用exectue时,它将doInBackground在单独的线程(不是Event Dispatch Thread)中运行doInBackground ,并将在事件分发线程中运行done方法。

因此,通过使用SwingWorker,您不必担心EDT中处理UI事件的内部问题以及另一个线程中耗时的任务。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM