图像的异步加载
图像的加载和显示是异步进行的,图像
的生产者(ImageProducer)传递给图像的消费者(ImageConsumer)一个与图像相关的位,因为图像的生产过程是一个异步行为,所以
AWT 也提供一个图像观察(ImageObserver),用来监视图像生产者的图像生产过程。
因为 java.awt.Component 实现 ImageObserver 接口,所以 AWT 中每个构件都是ImageObserver ,当一个给定的 ImageProducer 采取异步操作时,这个 ImageObserver 可以选择是否被更新。
现在看一个例子:
import java.net.URL;
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
public class ImageTestAppletSimple2
extends Applet {
private Image im;
public void init() {
im = getImage(getCodeBase(), "lena.jpg");
}
public void paint(Graphics g) {
System.out.println("drawing image");
System.out.println(g.drawImage(im, 0, 0, this));
}
}
当这个 Applet 第一次被调用时,将打印出下面的结果:
drawing image...
false
drawing image...
false
drawing image...
false
drawing image...
true
执
行结果说明 drawImage() 在第一次被调用时,没有图像被加载,drawImage() 只是向和图像相关的 ImageProducer
注册 ImageObserver,图像被完全加载前 drawImage() 方法返回 false 直到图像被完全加载返回 true。
当 drawImage()
返回之后,只要有图像的新的部分被加载,ImageObserver 中的 imageUpdate() 方法就会被调用。当
ImageObserver 是 AWT 构件时,Component.imageUpdate() 调用 repaint()
方法清除构件背景并调用 paint() 方法重绘刚刚得到的图像位。重复循环,ImageProducer 加载图像的下一块,调用
ImageObserver 的 imageUpdate()。当图像被完全加载时,ImageProducer 停止调用
ImageObserver 的 imageUpdate(),循环中断。
load -> imageUpdate() -> repaint() -> update() -> paint()
等待图像的完全加载
上面的例子介绍了图像的异步加载,现在介绍2个方法使图像完全加载前不显示。
·重载 ImageObserver 中的 imageUpdate() 方法,使其在图像完全加载前不调用 repaint()。
import
java.applet.Applet;
import
java.awt.Graphics;
import
java.awt.Image;
public
class
ImageTestAppletWithUpdate
extends
Applet {
private
Image im;
public
void
init() {
im
=
getImage(getCodeBase(),
"
lena.jpg
"
);
}
public
void
paint(Graphics g) {
g.drawImage(im,
0
,
0
,
this
);
}
public
boolean
imageUpdate(Image image,
int
flags,
int
x,
int
y,
int
w,
int
h) {
System.out.println(
"
imageUpdate():x=
"
+
x
+
"
,y=
"
+
y
+
"
,w=
"
+
w
+
"
,h=
"
+
h);
if
( (flags
&
ALLBITS)
==
0
) {
return
true
;
//
need more updates
}
else
{
repaint();
return
false
;
//
image is fully loaded
}
}
}
使用 java.awt.MediaTracker 类跟踪图像的加载,不必重载 imageUpdate() 方法。
import
java.net.URL;
import
java.applet.Applet;
import
java.awt.Graphics;
import
java.awt.Image;
import
java.awt.MediaTracker;
public
class
ImageTestAppletWithMediaTracker
extends
Applet {
private
Image im;
public
void
init() {
im
=
getImage(getCodeBase(),
"
lena.jpg
"
);
MediaTracker tracker
=
new
MediaTracker(
this
);
tracker.addImage(im,
0
);
try
{
tracker.waitForID(
0
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
System.out.print(
"
Image width =
"
+
im.getWidth(
this
));
System.out.println(
"
height =
"
+
im.getHeight(
this
));
}
public
void
paint(Graphics g) {
g.drawImage(im,
0
,
0
,
this
);
}
}
我们可以把使用 java.awt.MediaTracker 类将图像完全加载的方法包装成一个实用方法
/**
*//**
* 使用 java.awt.MediaTracker 将图像完全加载。
*
@param
component Component
*
@param
img Image
*/
public
static
void
waitForImage(Component component, Image img) {
MediaTracker tracker
=
new
MediaTracker(component);
try
{
tracker.addImage(img,
0
);
tracker.waitForID(
0
);
}
catch
(InterruptedException ex) {
ex.printStackTrace();
}
}