SwingWorker类解析

来源:互联网 发布:巴铁骗局 知乎 编辑:程序博客网 时间:2024/06/13 13:30

一      线程类别及为什么要使用SwingWorker

1.1      一个Swing开发人员将会和以下几种线程打交道

  • 初始线程:在标准的程序中,只有一个这样的线程:这个线程将调用程序主类中的main方法。在Swing程序中,初始线程主要作用是创建GUI,通过EventQueue的invokeLater方法或者invokeAndWait方法

EventQueue.invokeLater(new Runnable()) {    public void run() {        createAndShowGUI();    }}

  • 事件分派线程(Event dipatch thread   EDT):根据单一线程规则,所有的接触Swing组件的代码必须在该线程执行在该线程执行的事件必须是要能快速完成的,否则事件堆积起来将造成界面响应过慢。
  • 工作线程:通常执行所有消耗时间的任务


1.2   事件分派线程与工作线程:

这些约束意味着需要耗时操作的 GUI 应用程序至少需要以下两个线程:1) 执行长时间任务的工作线程; 2) 所有 GUI 相关活动的事件指派线程 (EDT)这涉及到难以实现的线程间通信。

SwingWorker 设计用于需要在后台线程中运行长时间运行任务的情况,并可在完成后或者在处理过程中向 UI 提供更新。SwingWorker 的子类必须实现 doInBackground() 方法,以执行后台计算。(当然也可以采用启动新线程完成耗时任务,但此时应该在线程中使用EventQueue.invokeLater方法来更新用户界面,步骤较为繁琐)


二   使用SwingWorker


2.1   后台任务的典型UI活动

  • 工作过程中更新UI显示进度
  • 工作完成后做最后的更新

2.2  工作流

工作流


SwingWorker 的生命周期中包含三个线程:


当前线程:在此线程上调用 execute() 方法。它调度 SwingWorker 以在 worker 线程上执行并立即返回。可以使用 get 方法等待 SwingWorker 完成。


Worker 线程:在此线程上调用 doInBackground() 方法。所有后台活动都应该在此线程上发生。要通知 PropertyChangeListeners 有关绑定 (bound) 属性的更改,请使用 firePropertyChange 和 getPropertyChangeSupport() 方法。默认情况下,有两个可用的绑定属性:state 和 progress。


事件指派线程:所有与 Swing 有关的活动都在此线程上发生。SwingWorker 调用 process 和 done() 方法,并通知此线程的所有 PropertyChangeListener。


通常,当前 线程就是事件指派线程。


在 worker 线程上调用 doInBackground 方法之前,SwingWorker 通知所有 PropertyChangeListener 有关对 StateValue.STARTED 的 state 属性更改。doInBackground 方法完成后,执行 done 方法。然后 SwingWorker 通知所有 PropertyChangeListener 有关对 StateValue.DONE 的 state 属性更改。


SwingWorker 被设计为只执行一次。多次执行 SwingWorker 将不会调用两次 doInBackground 方法。


2.3   具体使用方法

 1   实现SwingWorker<T,V>的子类  //该类为泛型类,产生类型为T的工作结果和类型为V的进度数据


  需要重写的方法

     doInBackground();  // 运行在工作线程中,编写执行耗时操作的逻辑代码,并以返回值来作为线程的执行结果。应在此方法中不时地调用publish()方法报告工作进度,几个publish()的调用会引起process()方法的一次调用成批处理


     process();     //运行在EDT中,接收一个包含几个中间结果的列表<V>,从列表中提取出数据可直接用于更新UI(通常process仅仅关注每次返回的最后一组值,使用  它来更新GUI):


     done();   // 运行在EDT中,任务完成后自动调用,典型地可以使用get()方法得到工作结果数据,对UI进行最后的更新

 

                                     注意:必须要重写的方法只有doInBackground


  2   实例化该子类,调用其execute方法启动该线程


2.4      类SwingWorker类 SwingWorker<T,V>详解


java.lang.Object
  继承者 javax.swing.SwingWorker<T,V>
类型参数:
T - 此 SwingWorker 的 doInBackground 和 get 方法返回的结果类型
V - 用于保存此 SwingWorker 的 publish 和 process 方法的中间结果的类型
所有已实现的接口:
Runnable, Future<T>, RunnableFuture<T>(前两个接口的简单封装)


因为实现了Runnable,所以有run方法,调用FutureTask.run()

因为实现了Future,所以有:

2.5   绑定属性和状态方法

SwingWorker支持bound properties,这个在与其他线程通信时很有作用。提供两个绑定属性:progress和state。progress和state可以用于触发在事件派发线程中的事件处理任务。
通过实现一个PropertyChangeListener,程序可以捕捉到progress,state或其他绑定属性的变化。

以下为相关的方法解读:

 voidaddPropertyChangeListener(PropertyChangeListener listener) //通常使用匿名类的做法,任务子类的方法
          将 PropertyChangeListener 添加到侦听器列表。

 voidfirePropertyChange(String propertyName, Object oldValue, Object newValue) 
          向所有已注册的侦听器报告绑定属性更新

 intgetProgress() 
          返回 progress 绑定属性。 PropertyChangeSupportgetPropertyChangeSupport() 
          返回此 SwingWorker 的 PropertyChangeSupport

protected  voidsetProgress(int progress) 
          设置 progress 绑定属性。

典例:使用ProgressBar更新显示进度,很方便地在工作线程与EDT之间进行通信

setProgress(100 * numbers.size() / numbersToFind);

task.addPropertyChangeListener(

new PropertyChangeListener() {public  void propertyChange(PropertyChangeEvent evt) //需要重写的方法{if ("progress".equals(evt.getPropertyName()))//得到属性的名称 {progressBar.setValue((Integer)evt.getNewValue())//得到属性最新对应的值;             }         }     });



更多关于SwingWorker方法的解析:http://www.oschina.net/uploads/doc/javase-6-doc-api-zh_CN/javax/swing/SwingWorker.html