-
Bug
-
Resolution: Duplicate
-
P3
-
None
-
1.4.1
-
x86
-
windows_2000
Name: jk109818 Date: 03/28/2003
FULL PRODUCT VERSION :
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
Java HotSpot(TM) Client VM (build 1.4.1_01-b01, mixed mode)
FULL OPERATING SYSTEM VERSION :
Microsoft Windows 2000 [Version 5.00.2195]
ADDITIONAL OPERATING SYSTEMS :
Linux
A DESCRIPTION OF THE PROBLEM :
The problem occurs when an animated gif is displayed in a
JEditorPane under text/html (e.g. img src=".."), and then
the component is hidden. The GIF continues to eat CPU
cycles, and the Image Animator thread lives on forever.
Reference bug 4302818
(http://developer.java.sun.com/developer/bugParade/bugs/4302
818.html) which is the same problem, except with JLabel's
and JButton's.
The test case loads a JFrame with some buttons. One toggles
appearance of a JLabel with an animated GIF, one toggles
appearance of a JEditorPane with an animated GIF. The final
button lists all the Image Animator threads. Toggling the
JLabel in and out will create and destroy Image Animator
threads as expected, but once the JEditorPane creates an
Image Animator thread it never goes away. I do not include
animated GIF's with this bug report, but the test case
references some images on the web. Placing the JEditorPane
in its own window that gets disposed has no effect, for
simplicity I did not do that in the test case.
The solution for bug #4302818 was to add "!isShowing() ||"
in the if block in imageUpdate for JLabel. A similar
statement was added to AbstractButton's imageUpdate, so
that it returns false if the component is not visible. I
tried this solution with JEditorPane but it was
unsuccessful... this is (apparently) because the image
observer for the animated gif in the HTML pane is not the
JEditorPane itself. I am unsure what class manages the
images references by HTML in editor panes.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Create and display a JEditorPane referencing an animated
image.
2. Hide and destroy the JEditorPane.
3. Note continued existence of an Image Animator thread.
EXPECTED VERSUS ACTUAL BEHAVIOR :
The Image Animator thread should go away once the component
is hidden.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
The Image Animator thread stack trace usually looks like the following:
"Image Animator 0" daemon prio=4 tid=0x008FF0E8 nid=0x584 waiting on condition
[d81f000..d81fd8c]
at java.lang.Thread.sleep(Native Method)
at sun.awt.image.GifFrame.dispose(Unknown Source)
at sun.awt.image.GifImageDecoder.readImage(Unknown Source)
at sun.awt.image.GifImageDecoder.produceImage(Unknown Source)
at sun.awt.image.InputStreamImageSource.doFetch(Unknown Source)
at sun.awt.image.ImageFetcher.fetchloop(Unknown Source)
at sun.awt.image.ImageFetcher.run(Unknown Source)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.URL;
import javax.swing.JButton;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.ImageIcon;
public class AnimTest extends JFrame {
static final String IMAGE1 = "http://www.google.com/logos/google2.gif";
static final String IMAGE2 = "http://www.google.com/logos/giroux3.gif";
JButton labelButton;
JButton paneButton;
public AnimTest() {
super("Testing Animated Icons");
getContentPane().setLayout(new FlowLayout());
// add animated label toggle button
labelButton = new JButton("Toggle Label On");
labelButton.addActionListener(new MyLabelListener());
getContentPane().add(labelButton);
// add animated label html pane toggle button
paneButton = new JButton("Toggle Pane On");
paneButton.addActionListener(new MyPaneListener());
getContentPane().add(paneButton);
// add thread dump button
JButton threadButton = new JButton("Threads");
threadButton.addActionListener(new ThreadListener());
getContentPane().add(threadButton);
}
/** Add JLabel with text and animated icon. */
protected class MyLabelListener extends MyToggleListener {
protected void prepareComponent() {
component = new JLabel("Label");
try {
ImageIcon icon = new ImageIcon(new URL(IMAGE1));
((JLabel)component).setIcon(icon);
} catch (java.net.MalformedURLException _ex) {
_ex.printStackTrace();
}
labelButton.setText("Toggle Label Off");
}
protected void destroyComponent() {
((JLabel)component).setIcon(null);
labelButton.setText("Toggle Label On");
}
}
/** Add JEditorPane with an img tag referencing an animated image. */
protected class MyPaneListener extends MyToggleListener {
protected void prepareComponent() {
String src = IMAGE2;
JEditorPane imagePane = new JEditorPane();
imagePane.setContentType("text/html");
imagePane.setEditable(false);
imagePane.setText
("<html><body>Pane<img src=\"" + src
+ "\"></body></html>");
component = imagePane;
paneButton.setText("Toggle Pane Off");
}
protected void destroyComponent() {
JEditorPane imagePane = (JEditorPane) component;
imagePane.setDocument
(imagePane.getEditorKit().createDefaultDocument
());
imagePane.getEditorKit().deinstall(imagePane);
paneButton.setText("Toggle Pane On");
}
}
protected abstract class MyToggleListener implements ActionListener {
boolean toggle = true;
Component component = null;
public void actionPerformed(ActionEvent ae) {
if (toggle) {
// create component
prepareComponent();
// add component
getContentPane().add(component);
toggle = false;
} else {
// clean up component
destroyComponent();
// remove component
getContentPane().remove(component);
component = null;
toggle = true;
}
validate();
repaint();
}
/** Create component. */
protected abstract void prepareComponent();
/** Clean up component. */
protected abstract void destroyComponent();
}
protected class ThreadListener implements ActionListener {
public void actionPerformed(ActionEvent ae) {
System.out.println("\nAnimator Threads\n----------------
");
Thread[] threads = new Thread[Thread.activeCount()+2];
Thread.enumerate(threads);
for (int x=0; x < threads.length; x++) {
if (threads[x] != null &&
threads[x].getName().indexOf
("Animator") > -1)
{
System.out.println(threads
[x].getName());
}
}
}
}
public static void main(String[] args) {
AnimTest frame = new AnimTest();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 200);
frame.setLocation(200, 200);
frame.show();
}
}
---------- END SOURCE ----------
CUSTOMER WORKAROUND :
Unknown. Overriding the imageUpdate in JEditorPane to
return false when not visible does not work, since it isn't
being called for animated GIF's referenced through HTML
source in the pane. I don't know what class is being called.
(Review ID: 180330)
======================================================================
- duplicates
-
JDK-4821632 Displaying Animated Gif in JEditorPane causes nonstop CPU usage
-
- Resolved
-