Applet Failing After First Load

With every applet I’ve ever written (so far as I can recall), I’ve had the following problem:

It runs fine the first time. Then, if I open it again in the same Internet browser when any window of the Internet browser is open, the applet is just empty space. This didn’t happen with an applet I checked that was written by some else, so I assume it’s a problem with my code.

Shutting all the windows in the Internet Browser and then opening up the page with my applet again works fine. I assume that Internet Browsers cache the applet somehow, but this doesn’t cause a problem with other people’s code.

I’m using Java 5, but I’ve always had this same problem. This occurs with both Mozilla Firefox and Microsoft Internet Explorer.

Here’s the parts of my code that I believe are relevant:

/**	<p>This class runs the Nanotron applet.
	@author Steven Fletcher
	@since 2006/07/10
	@version 2006/08/02*/
public class Nanotron extends JApplet implements Runnable {
//APPLET/////////////////////////////////////////////////////////////////////////////////
/**	Destroys this applet.*/
public void destroy() {
	//stop the main loop
	synchronized(this) {
		bDestroyApplet = bPauseApplet = true;
	}
} //end destroy

/**	Initializes this applet.*/
public void init() {
//do some initialization
//...
} //end init

/**	Starts this applet.*/
public void start() {
	//focus on this applet so that keyboard input is accepted
	requestFocus();

	//unpause the main loop
	synchronized(this) {
		bPauseApplet = false;
	}

	//start the main loop
	//NOTE: The main loop can't be started during init or start will never be called.
	new Thread(this).start();
} //end start

/**	Stops this applet.*/
public void stop() {
	//stop the main loop
	synchronized(this) {
		bPauseApplet = true;
	}
} //end stop

//RUNNABLE///////////////////////////////////////////////////////////////////////////////
/**	Executes the game's main loop.*/
public void run() {
	while(true) {
		//check for the end of the loop
		synchronized(this) {
			//do nothing while the applet is paused
			while(bPauseApplet) {
				//if the applet should be destroyed, stop
				if(bDestroyApplet)
					return;

				//sleep
				try {
					Thread.sleep(100);
				} catch(InterruptedException exception) {}
			}
		};

		//do the actual loop
//...
	} //end while forever
} //end run

//VARIABLES//////////////////////////////////////////////////////////////////////////////
//multithreading
private boolean bPauseApplet = false, bDestroyApplet = false;
} //end class Nanotron

The following “minimal” code does, in fact, not have this problem. All it does is display an annoying flashing blue applet though.

I still don’t know what part of my actual code causes the problem though.

/**	<p>This class runs the Nanotron applet.
	@author Steven Fletcher
	@since 2006/07/10
	@version 2006/08/02*/
public class Nanotron extends JApplet implements Runnable {
//APPLET/////////////////////////////////////////////////////////////////////////////////
/**	Destroys this applet.*/
public void destroy() {
} //end destroy

/**	Initializes this applet.*/
public void init() {
} //end init

/**	Paints this Applet.
	@param g the Graphics object to paint to*/
public void paint(final Graphics g) {
	super.paint(g);
	g.setColor(Color.blue);
	g.fillRect(0, 0, getWidth(), getHeight());
} //end paint

/**	Starts this applet.*/
public void start() {
	//start the main loop
	//NOTE: The main loop can't be started during init or start will never be called.
	new Thread(this).start();
} //end start

/**	Stops this applet.*/
public void stop() {
} //end stop

//RUNNABLE///////////////////////////////////////////////////////////////////////////////
/**	Executes the game's main loop.*/
public void run() {
	while(true) {
		repaint();
	} //end while forever
} //end run
} //end class Nanotron

I’ve done some testing (by commenting out various sections of the code). In the “unimportant” parts of the code that I didn’t post, I created some other singleton classes that use static variables. Could it be that the combination of the static variables and the rather trivial multithreading is causing the problem? If you run two copies of an applet in the same browser, do they share static variables somehow? If they do, that kind of sucks.

If that’s the problem, the only potential solution I see is to make all the non-final variables static. And that seems a little silly - those variables are static for a reason.

if your applet isn’t huge, you could slowly upgrade that minimal case and see from what code problems appears. Seems worth the time if all your applets suffer from this problem.

That’s probably the only solution. It’s more of a hassle than I would like, but it’s probably the only way.

I’ve since discovered that it’s only the Swing components within the applet that don’t get drawn. If I fill the applet with blue in the paint method and draw the Swing components, the blue appears but the Swing components don’t.

I know there were some problems with CardLayout in previous releases of Java, so I tried using FillLayout instead. It didn’t seem to help.

Does anyone else have this problem with Swing components in applets?

I figured out what the problem was and fixed it.

All of my Swing components (except the applet itself) were created in a singleton class. The static variables apparently get shared between applets. This seemed to be what was screwing things up. All I had to do was make the singleton class a non-singleton.

Also, I made a singleton class representing the state of the game into a non-singleton so that multiple copies of the game can be run simultaneously.

That is really wierd, I thought applets ran in their own VM & so static variables are not shared? I just read the API docs about java.awt.EventQueue http://java.sun.com/j2se/1.5.0/docs/api/java/awt/EventQueue.html and it talks about applet contexts, what are they? Is it onlyu Swing static vars that are shared?

It’s all static variables. I had to change the static variables for the state of the game as well. I would have the first version of the applet in the game, and then open a second version. All the enemies would disappear, and the player’s sprite would appear in the top-left corner. The only way I can explain that behavior is that the static variables were being shared.

I read somewhere that applets running at the same time share the same ClassLoader, so that might be the problem. If they’re sharing the same ClassLoader, they must be running in the same VM.

It only seems to be for applets being run from the same url in the same brower though. I could run 2 copies of the applet from 2 different pages with no problems.

Now that I’ve taken out all the static variables that change during the game, there’s no problem anymore. It was kind of weird though.

A web browser creates only one VM (at least IE and Firefox do it this way). Thus you need to be very careful when same applet runs twice in same web browser. Both instances will share static fields.

I guess this is another case of “don’t use static variables” wisdom. It can be convenient to use a static variable once in a while for ease of reference, but really it’s bad practice. Static variables should generally be final and fully immutable (like String). That aside, I still use bad static references sometimes ::slight_smile: