java.awt.MediaTracker
is a utility class that simplifies life if we have to wait for one or
more images to be loaded before they’re displayed. A
MediaTracker
monitors the preparation of an image
or a group of images and lets us check on them periodically, or wait
until they are completed. MediaTracker
uses the
ImageObserver
interface internally to receive
image updates.
The following
applet, TrackImage
,
uses a MediaTracker
to wait while an image is
prepared. It shows a "Loading . . .”
message while it’s waiting. (If you are retrieving the image
from a local disk or very fast network, this message might go by
quickly, so pay attention.)
//file: TrackImage.java import java.awt.*; public class TrackImage extends javax.swing.JApplet implements Runnable { final int MAIN_IMAGE = 0; Image image; MediaTracker tracker; boolean loaded = false; Thread thread = null; String message = "Loading..."; public void init( ) { image = getImage(getClass( ).getResource(getParameter("image"))); tracker = new MediaTracker(this); tracker.addImage(image, MAIN_IMAGE); } public void start( ) { if (!tracker.checkID(MAIN_IMAGE)) { thread = new Thread(this); thread.start( ); } } public void stop( ) { thread.interrupt( ); thread = null; } public void run( ) { repaint( ); try { tracker.waitForID(MAIN_IMAGE); } catch(InterruptedException e) {} if (tracker.isErrorID(MAIN_IMAGE)) message = "Error"; else loaded = true; repaint( ); } public void paint(Graphics g) { if (loaded) g.drawImage(image, 0, 0, this); else { g.drawRect(0, 0, getSize().width - 1, getSize( ).height - 1); g.drawString(message, 20, 20); } } }
From its init( )
method, TrackImage
requests its image and creates
a MediaTracker
to manage it. Later, after the
applet is started, TrackImage
fires up a thread to
wait while the image is loaded. Note that we do not do this in
init( )
because it would be rude to do anything
time-consuming there; it would take up time in a thread that we
don’t own. In this case, waiting in init( )
would be especially bad because paint( )
would
never get called and our “loading” message wouldn’t
be displayed; the applet would just hang until the image loaded.
It’s often better to create a new thread for initialization and
display a startup message in the interim. (If you’re not
familiar with applets, you may want to take a look at Chapter 20, at this point.)
When we construct a MediaTracker
, we give it a
reference to our component (this
). After creating
a MediaTracker
, we assign it images to manage.
Each image is associated with an integer
identifier we’ll use later for
checking on its status. Multiple images can be associated with the
same identifier, letting us manage them as a group. The value of the
identifier is also used to prioritize loading when
waiting on multiple sets of images; lower IDs have higher priority.
In this case, we want to manage only a single image, so we created
one identifier called MAIN_IMAGE
and passed it as
the ID for our image in the call to addImage( )
.
In our applet’s start( )
method, we call the
MediaTracker
’s checkID( )
routine with the ID of the image
to see whether it’s already been loaded. If it hasn’t,
the applet fires up a new thread to fetch it. The thread executes the
run( )
method, which calls the
MediaTracker
waitforID( )
routine and blocks on the image, waiting for it to finish loading.
The loaded
flag tells paint( )
whether to display our status message or the actual image. We do a
repaint( )
immediately upon entering run( )
to display the “Loading . . .” status, and
again upon exiting to change the display. We test for errors during
image preparation with isErrorID( )
and
change the status message if we find one.[48]
This may seem like a lot of work to go through just to put up a
status message while loading a single image.
MediaTracker
is more valuable when we are working
with many images that have to be available before we can begin parts
of our application. It saves us from implementing a custom
ImageObserver
for every application. In the
future, MediaTracker
should also be able to track
the status of audio clips and
other kinds of media (as its name
suggests).
[48] In early
Java 2 releases, appletviewer
may throw an access exception when you close down the
applet. The exception occurs when
TrackImage
’s stop()
method attempts to call the interrupt(
)
method on the image-loading thread. This is a
problem with appletviewer
—the example runs
fine as a Java Plug-in applet. (See Chapter 20 for
more information about the Java Plug-in.)