Using a MediaTracker

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.)

Get Learning Java now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.