Spec-Zone .ru
спецификации, руководства, описания, API
|
|
Best Practices For Applet Development
|
Contents
Applets have a complex runtime environment and several issues need to be considered to ensure that applets run predictably on various browsers and versions of Java Plug-ins. This document describes the best practices for applet development and deployment .
Values stored in the applet could persist between invocations, if the memory acquired by the class loader cache isn't needed for other purposes. But you can't depend on that behavior. In general, applets should be stateless. If persistent storage is needed, use browser cookies.
start
method as quickly as possibleIf start
doesn't terminate, stop
can't be called. That's important, because garbage collection occurs after the destroy
method terminates. If the applet lingers in the start
method, then the applet may not be torn down properly. (It will be torn down, and garbage collection will occur, but resources acquired during applet initialization may not be properly released.)
For a computationally-intensive app like the Runnable
interface, do the heavy lifting in the run
method it requires, and launch a separate thread to do the actual work, as shown in this abstract from the
public class Clock extends Applet implements Runnable { private volatile Thread timer; // The thread that displays the clock ... public void start() { timer = new Thread(this); // Create the thread and start it timer.start(); } public void stop() { timer = null; // Release the thread resource } public void run() { Thread me = Thread.currentThread(); while (timer == me) { try { Thread.currentThread().sleep(100); } catch (InterruptedException e) { } repaint(); } } ...
Here, the action is to pause the Clock instance that's running in the new thread (hence the need to store a pointer to it.) Applets that don't need to do all that can simply put their processing code into the run
method.
For an interactive app like the
public class SpreadSheet extends Applet implements MouseListener, KeyListener // Event processing { public void init() { ... addMouseListener(this); addKeyListener(this); } ... public void start() { isStopped = false; } public void stop() { isStopped = true; } public void keyTyped(KeyEvent e) { // Invoked when an event occurs ... } public void mousePressed(MouseEvent e) { ... } ... class CellUpdater extends Thread { ... public void run() { ... if (!target.app.isStopped && !target.paused) { target.app.repaint(); }
In this particular implementation, each cell has it's own update thread. Updating is paused when a cell is selected, and only stops completely when the applet terminates. The important point is that the applet's start
and stop methods only keep track of applet state. Most of the time is spent in the underlying event-processing thread, waiting for the user's keystroke or mouseclick. The applet's real work then occurs in response to one of those events.
An ID defines the namespace, and ensures proper naming at all levels of the data hierarchy:
<applet id="myApplet" name="myApplet" ...
Truly stateless applets don't depend on values previously stored in static variables. Since you can't depend on those values to be retained, it's a good idea to create stateless applets. But the user can still store state. It's just that store the data where it belongs--with the user, rather than in the applet code.
To implement a stateless app, access browser cookies or launch with JNLP to use Java Web Start muffins, so the applet gets it's initial settings from persistent storage, rather than using values stored in the program.
To ensure that your applet is stateless, use the classloader_cache attribute to disable the cache. For example:
<applet ... classloader_cache="false"
That setting ensures that the applet is stateless, and that it is truly decoupled from the remainder of the system and from other instances of the applet. It also ensures that the applet runs the exact same way every time, since it won't be affected by state that has been inadvertently retained.
Note:
In the rare case that you expect your users to re-run the same applet repeatedly, you might consider leaving the cache enabled for production for the sake of performance, but disable it during development to ensure quality.
To prevent thread contention, don't update the Swing or AWT GUI from javascript directly. Instead, set up a proxy that forwards the request to the appropriate dispatch thread:
javax.swing.SwingUtilities.invokeLater(Runnable)
java.awt.EventQueue.invokeLater(Runnable)
Minimize the time taken to call from Java into javascript, and from javascript into Java. Don't do long-running work in such calls, or you risk a deadlock. To keep the calls short:
When calling into Java, don't make calls back into javascript if you can possibly help it, and vice versa. In that original plugin, doing so used to lock up the browser. That shouldn't happen anymore, but round-trip calls do introduce significant delays in processing time.
When a javascript function needs the applet to do something, the best practice is to return a value that tells the applet to do it, and then call back with the results, or else use invokeLater
to minimize traffic tie ups.
The Java platform has powerful multi-threading capabilities that you can take advantage of with classes like Thread, Swing invokeLater
, and AWT invokeLater
, as well as the new ThreadPoolExecutor class that maintains a background thread pool.
Copyright
©2008 |
|