圖像的異步加載
圖像的加載和顯示是異步進行的,圖像
的生產(chǎn)者(ImageProducer)傳遞給圖像的消費者(ImageConsumer)一個與圖像相關(guān)的位,因為圖像的生產(chǎn)過程是一個異步行為,所以
AWT 也提供一個圖像觀察(ImageObserver),用來監(jiān)視圖像生產(chǎn)者的圖像生產(chǎn)過程。
因為 java.awt.Component 實現(xiàn) ImageObserver 接口,所以 AWT 中每個構(gòu)件都是ImageObserver ,當(dāng)一個給定的 ImageProducer 采取異步操作時,這個 ImageObserver 可以選擇是否被更新。
現(xiàn)在看一個例子:
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));
??}
}
當(dāng)這個 Applet 第一次被調(diào)用時,將打印出下面的結(jié)果:
drawing?image...
false
drawing?image...
false
drawing?image...
false
drawing?image...
true
執(zhí)
行結(jié)果說明 drawImage() 在第一次被調(diào)用時,沒有圖像被加載,drawImage() 只是向和圖像相關(guān)的 ImageProducer
注冊 ImageObserver,圖像被完全加載前 drawImage() 方法返回 false 直到圖像被完全加載返回 true。
當(dāng) drawImage()
返回之后,只要有圖像的新的部分被加載,ImageObserver 中的 imageUpdate() 方法就會被調(diào)用。當(dāng)
ImageObserver 是 AWT 構(gòu)件時,Component.imageUpdate() 調(diào)用 repaint()
方法清除構(gòu)件背景并調(diào)用 paint() 方法重繪剛剛得到的圖像位。重復(fù)循環(huán),ImageProducer 加載圖像的下一塊,調(diào)用
ImageObserver 的 imageUpdate()。當(dāng)圖像被完全加載時,ImageProducer 停止調(diào)用
ImageObserver 的 imageUpdate(),循環(huán)中斷。
load -> imageUpdate() -> repaint() -> update() -> paint()
等待圖像的完全加載
上面的例子介紹了圖像的異步加載,現(xiàn)在介紹2個方法使圖像完全加載前不顯示。
·重載 ImageObserver 中的 imageUpdate() 方法,使其在圖像完全加載前不調(diào)用 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();
????}
??}