使用SwingWorker之一
来源:互联网 发布:车辆二级检测数据 编辑:程序博客网 时间:2024/06/04 19:17
本文演示了一个使用SwingWorker类创建和管理任务线程的例子,描述了如何避免编写运行缓慢、感觉迟钝、容易失去响应的用户界面。这个演示例子叫Image Search,它展示了如何使用SwingWorker API来和网站Flickr进行交互、搜索并下载图像。
如果需要理解Swing Ui的基本概念,包括事件处理和侦听等UI编程,可以参照前面的文章,或从Sun官方网站下载阅读Java教程的Swing部分。
演示程序介绍
Image Search执行的耗时任务是访问Flickr网站服务,该任务不应该在EDT上执行。Image Search程序搜索Flickr站点,搜索匹配用户输入的查询条件的图像,下载匹配图形的缩略图。当用户从缩略图列表中选择某缩略图时,它将下载该图的原始图片。该演示程序使用SwingWorker类作为任务线程,从而避免了在EDT上执行这些耗时任务。
当用户输入查询条件时,程序在Flickr网站请求一个图像查询。如果有符合查询条件的图像,程序下载上限为100个的缩略图像。可以修改程序改变下载图像的数目。搜索和下载图像的同时,有一进度条显示搜索进度。图1显示了查询字段和进度条:
每当程序成功下载一个缩略图片后,就添加到一个JList组件中,图片从Flickr站点到达后就被添加列表中。程序使用SwingWorker的一个实例,程序能在每个图片到达时添加到列表,而不用等待所有的图片都到达。图2显示列表中的图片:
当从列表选择一个图片,程序将下载该图片的原始图片,并显示在列表的下面。当大图片下载时,另一进度条将显示下载进度。图3显示列表和图片下载进度条。
最后,当所有图片数据下载完毕后,程序在列表下方显示图片。
程序使用SwingWorker来完成所有图片搜索和下载任务。另外,程序还演示了如何取消任务,如何在任务完成之前获得即时结果。该程序有两个SwingWorker的子类:ImageSearcher和ImageRetriever。ImageSearcher类负责搜索和获取图片列表中的缩略图,ImageRetriever类负责用户从列表选择时下载原始版本的图片。本文用这个类来描述SwingWorker类的主要功能。图4显示程序的整个外观。
一个Swing程序中一般有下面三种类型的线程:
* 初始化线程(Initial Thread)
* UI事件调度线程(EDT)
* 任务线程(Worker Thread)
每个程序必须有一个main方法,这是程序的入口。该方法运行在初始化或启动线程上。初始化线程读取程序参数并初始化一些对象。在许多Swing程序中,该线程主要目的是启动程序的图形用户界面(GUI)。一旦GUI启动后,对于大多数事件驱动的桌面程序来说,初始化线程的工作就结束了。
Swing程序只有一个用EDT,该线程负责GUI组件的绘制和更新,通过调用程序的事件处理器来响应用户交互。所有事件处理都是在EDT上进行的,程序同UI组件和其基本数据模型的交互只允许在EDT上进行,所有运行在EDT上的任务应该尽快完成,以便UI能及时响应用户输入。
Swing编程时应该注意以下两点:
1.从其他线程访问UI组件及其事件处理器会导致界面更新和绘制错误。
2.在EDT上执行耗时任务会使程序失去响应,这会使GUI事件阻塞在队列中得不到处理。
3.应使用独立的任务线程来执行耗时计算或输入输出密集型任务,比如同数据库通信、访问网站资源、读写大树据量的文件。
总之,任何干扰或延迟UI事件的处理只应该出现在独立任务线程中;在初始化线程或任务线程同Swing组件或其缺省数据模型进行的交互都是非线程安全性操作。
SwingWorker类帮你管理任务线程和Swing EDT之间的交互,尽管SwingWorker不能解决并发线程中遇到的所有问题,但的确有助于分离Swing EDT和任务线程,使它们各负其责:对于EDT来说,就是绘制和更新界面,并响应用户输入;对于任务线程来说,就是执行和界面无直接关系的耗时任务和I/O密集型操作。
Image Search示例的主类是MainFrame,从其main方法启动。许多程序使用下面方法启动界面,但这是错误的启动UI界面的方法:
public class MainFrame extends javax.swing.JFrame {
...
new MainFrame().setVisible(true);
}
}
尽管这种错误出现在开始,但仍然违反了不应在EDT外的其他线程同Swing组件交互的原则。这个错误尤其容易犯,线程同步问题虽然不是马上显示出来,但是还要注意避免这样书写。
正确启动UI界面应该如下:
...
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MainFrame().setVisible(true);
}
});
}
}
使用NetBeans IDE的开发者应该对这段代码很熟悉,NetBeans通常会自动生成这段代码。这段启动代码虽然和SwingWorker没有直接关系,但是这个编程范式很重要。SwingUtilities类包含一些静态方法帮你同UI组件交互,其中invokeLater方法意思是在EDT上执行其Runnable任务。Runnable接口定义了可作为独立线程执行的任务。
在初始化线程中使用invokeLater方法能正确的初始化程序界面。就像前面文章所提到的,此方法是异步执行的,也就是说调用会立即返回。创建界面后,大部分初始化线程基本上就结束了。
通常有两种办法调用此方法:
* SwingUtilities.invokeLater
* EventQueue.invokeLater
两个方法都是正确的,选择任何一个都可以。实际上,SwingUtilities版只是一个薄薄的封装方法,它直接转而调用EventQueue.invokeLater。因为Swing框架本身经常调用SwingUtilities,使用SwingUtilities可以减少程序引入的类。
另种将任务放到EDT执行的方法是SwingUtilities.invokeAndWait,不像invokeLater,invokeAndWait方法是阻塞执行的,它在EDT上执行Runnnable任务,直到任务执行完了,该方法才返回调用线程。
invokeLater和invokeAndWait都在事件派发队列中的所有事件都处理完之后才执行它们的Runnable任务,也就是说,这两个方法将Runnable任务放在事件队列的末尾。
注意:虽然可以在其他线程上调用invokeLater,也可以在EDT上调用invokeLater,但是千万不要在EDT线程上调用invokeAndWait方法!很容易理解,这样做会造成线程竞争,程序就会陷入死锁。
幸运的是,不会仅仅因为有复杂的任务、计算或输入输出密集任务需要作为GUI事件处理任务执行,Swing的性能就要有所降低。毕竟有许多桌面程序执行耗时任务,比如处理电子表格公式、跨越网络查询数据库、通过Internet向其他程序发送信息。即使有这些任务,界面仍然可以让用户感觉到响应灵活、快捷。编写响应灵活的程序需要创建和管理独立于EDT的线程。
在Image Search程序中,有两个事件如果完全在EDT上处理就会降低界面的响应速度:图像搜索处理和选中图片下载处理。
两个事件处理都要访问Web服务,这些服务通常要许多秒后才能响应,在此期间,如果程序在EDT上进行Web服务交互,用户就不能取消搜索或者同界面交互,像这两种都不应该在EDT上运行。
图5显示了在A和B点之间,EDT不能处理UI事件,AB两点之间代表了程序访问Flickr网站Web服务的IO操作时间:
- 使用SwingWorker之一
- 使用SwingWorker之一
- 使用SwingWorker之一
- 使用SwingWorker之一
- 使用SwingWorker之一
- 使用SwingWorker之二
- 使用SwingWorker之三
- 使用SwingWorker之二
- 使用SwingWorker之三
- SwingWorker的使用
- SwingWorker的使用
- 使用SwingWorker之二
- 使用SwingWorker之三
- 使用SwingWorker之二
- 使用SwingWorker之三
- SwingWorker的使用
- SwingWorker的使用一
- SwingWorker
- ASP.NET中Get和Post的用法 Request.QueryString,Request.Form,Request.Params的区别
- 按照数组的形式排序+条件切换切换查询
- 程序判断Windows系统是32bit还是64bit
- Hadoop dfs -put 失败
- 归去来兮辞
- 使用SwingWorker之一
- ToString格式化
- Flex调用Javascript中多重对象的方法问题
- ArcCatalog中Add Spatial Database Connection
- 一周表情。。。
- OUTLOOK问题解析1
- iphone 开发经典入门
- web.py+sqlite写的简单留言本
- 第一次来CSDN,很不容易