Java-使用SwingWorker在工作线程更新主线程UI

Swing注意事项:

​ 在Java编程中会用到Swing来绘制界面,但是由于Swing线程不安全,所以如果进行一些在子线程中动态更新UI的操作时,会出现子进程结束返回时UI才变化的情况(例如在子线程中收发文件同时更新UI进度条显示,如果在子线程中更新UI会造成只有在文件传输完成的时候进度才从0一下跳到100的状况)。所以在进行Swing更新操作的时候,要注意: 1.不要阻塞UI绘制进程(将耗时操作放在线程中进行)2.不要在线程中对UI进行更新。 如果需要在子线程中动态更新UI的话,可以使用Swingworker来进行进度更新等操作。

SwingWorker使用:

​ SwingWorker可以实现在子线程对UI进行更新,可以自动管理任务线程和EDT之间的交互,当我们需要创建子线程实现耗时操作并同时更新UI时,我们可以自己创建一个SwingWorker的子类并重写其中的函数来实现我们的需求,下面就以接收文件并在UI显示文件接收进度这个需求来讲解一下SwingWorker的使用方法。

Swing结构:
class MySwingWorker extends SwingWorker<Boolean,Integer>{

    @Override
    protected Boolean doInBackground() throws Exception {
        return false;
    }

    @Override
    protected void process(List<Integer> chunks) {
        super.process(chunks);
    }

    @Override
    protected void done() {
        super.done();
    }
}

​ 当我们继承SwingWorker的时候一般会重写doInBackground();process(List chunks);done()这三个函数,还需要用到publish()以及get()函数,我们将接收文件的任务放在这里执行,并在执行的过程中不断调用publish()函数来更新任务进度给process()函数进行处理,这样就将任务线程中的进度变化传递出来,再通过监听变量的方法来实现UI更新,当doInBackground()执行完毕后会通过done()进行收尾工作,可以使用get()函数来获取doInBackground()的返回值,判断任务完成情况。

​ 我们看到继承SwingWorker需要声明两个类型参数:T和V,其中T参数为doInBackground()和get()函数的返回值,也就是函数执行完毕的返回值;V为publish到process函数中的数据类型,也就是需要动态更新的数据类型。下面以文件接收进度更新为例展示SwingWorker()用法:

SwingWorker使用:
class MySwingWorker extends SwingWorker<Boolean,Integer>{
    
    @Override
    protected Boolean doInBackground() throws Exception {
        while(/*文件未接收完毕*/){
            //接收文件数据包
            ratio=receive();
            System.out.println("文件接收了" + ratio + "%\n");    
            publish(ratio);//将文件接收进度传递给process
        }
        if(ratio==100)return true;//返回值
        else return false;
    }

    @Override
    protected void process(List<Integer> chunks) {
        super.process(chunks);
        for (int i :chunks)
        {
            this.setProgress(i);//设置传输进度,注意progress参数的取值为[0,100]
        }
    }

    @Override
    protected void done() {
        try {
            Boolean result = get();//获取返回值
            if (result) {
                JOptionPane.showMessageDialog(null, "文件接收成功!");
            } else {
                JOptionPane.showMessageDialog(null, "文件接收失败!");
            }
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

​ 根据伪代码我们可以对SwingWorker的工作方式有一个理解,即在doInBackground()中执行任务的同时不断地publish数据给process进行更新,最后以done函数进行收尾,下面使用属性监听将SwingWorker中更新的进度更新在UI界面中:

class MyPCListener implements PropertyChangeListener {
            @Override
            public void propertyChange(PropertyChangeEvent evt) {
                if("progress"==evt.getPropertyName()){
                    int progress = (Integer)evt.getNewValue();
                    jpb.setValue(progress);
                    jl.setText("文件已接收:"+progress+"%");
                }
            }
        }

​ 在UI线程对SwingWorker中的属性变化进行监听就可以实现动态更新任务进度条了:

MySwingWorker msw=new MySwingWorker(file);
msw.addPropertyChangeListener(new MyPCListener());//设置监听
msw.execute();//开始执行任务

你可能感兴趣的:(Java-使用SwingWorker在工作线程更新主线程UI)