Fixes Issues #74 & #790.
Adds Widget.onUnload() and clarifies the correct usage of onDetach(). An
assertion has also been added to setParent() to check the value of
isAttached() when running in hosted mode.
Patch by: bobv
Review by: knorton
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@990 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/src/com/google/gwt/user/client/ui/Widget.java b/user/src/com/google/gwt/user/client/ui/Widget.java
index 5211ea2..d80321d 100644
--- a/user/src/com/google/gwt/user/client/ui/Widget.java
+++ b/user/src/com/google/gwt/user/client/ui/Widget.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2006 Google Inc.
+ * Copyright 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
@@ -15,6 +15,7 @@
*/
package com.google.gwt.user.client.ui;
+import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventListener;
@@ -72,9 +73,15 @@
/**
* This method is called when a widget is attached to the browser's document.
- * It must not be overridden, except by {@link Panel}. To receive
- * notification when a widget is attached to the document, override the
- * {@link #onLoad} method.
+ * To receive notification after a Widget has been added from the
+ * document, override the {@link #onLoad} method.
+ *
+ * <p>
+ * Subclasses that override this method must call
+ * <code>super.onAttach()</code> to ensure that the Widget has been
+ * attached to the underlying Element.
+ * </p>
+ *
* @throws IllegalStateException if this widget is already attached
*/
protected void onAttach() {
@@ -96,7 +103,16 @@
/**
* This method is called when a widget is detached from the browser's
- * document. It must not be overridden, except by {@link Panel}.
+ * document. To receive notification before a Widget is removed from the
+ * document, override the {@link #onUnload} method.
+ *
+ * <p>
+ * Subclasses that override this method must call
+ * <code>super.onDetach()</code> to ensure that the Widget has been
+ * detached from the underlying Element. Failure to do so will result
+ * in application memeroy leaks due to circular references between DOM
+ * Elements and JavaScript objects.
+ * </p>
*
* @throws IllegalStateException if this widget is already detached
*/
@@ -105,20 +121,32 @@
throw new IllegalStateException(
"Should only call onDetach when the widget is attached to the browser's document");
}
- attached = false;
-
- // Clear out the element's event listener (breaking the circular
- // reference between it and the widget).
- //
- DOM.setEventListener(getElement(), null);
+
+ // Give the user a chance to clean up, but don't trust the code to not throw
+ try {
+ onUnload();
+ } finally {
+ attached = false;
+
+ // Clear out the element's event listener (breaking the circular
+ // reference between it and the widget).
+ DOM.setEventListener(getElement(), null);
+ }
}
/**
- * This method is called when the widget becomes attached to the browser's
- * document.
+ * This method is called immediately after a widget becomes attached to the
+ * browser's document.
*/
protected void onLoad() {
}
+
+ /**
+ * This method is called immediately before a widget will be detached from the
+ * browser's document.
+ */
+ protected void onUnload() {
+ }
/**
* Sets this object's browser element. Widget subclasses must call this method
@@ -181,9 +209,13 @@
if (parent == null) {
if (oldParent != null && oldParent.isAttached()) {
onDetach();
+ assert !isAttached() :
+ "Failure of " + GWT.getTypeName(this) + " to call super.onDetach()";
}
} else if (parent.isAttached()) {
onAttach();
+ assert isAttached() :
+ "Failure of " + GWT.getTypeName(this) + " to call super.onAttach()";
}
}
}