From: Xavier Ducrohet Date: Fri, 9 Jul 2010 19:48:04 +0000 (-0700) Subject: Fix a memory leak in the Graphical Layout Editor. X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=a46c5e60473548bbfa94f526ef68247b1470ca28;p=android-x86%2Fsdk.git Fix a memory leak in the Graphical Layout Editor. The rendering requires a looper, but never actually uses it. Some views (like scrollView) make use of messages during rendering putting messages into the looper message queue which was never read or emptied. In the case of the scrollview, the message actually contains a reference to the scrollview, which would then leak (with all its children views) The fix is to delete the looper that was created. This must be done by reflection as there's no public access to it, and this must be done from ADT so that all versions of layoutlib get the fix. Change-Id: I998ad0ec17e77e36a42d77f8ab888917a9ff6441 --- diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java index 45a56d7c3..06a7ba4a6 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle1/GraphicalLayoutEditor.java @@ -721,6 +721,9 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette configuredProjectResources, frameworkResources, projectCallback, null /* logger */); + // post rendering clean up + bridge.cleanUp(); + // update the UiElementNode with the layout info. if (result.getSuccess() == ILayoutResult.SUCCESS) { BufferedImage largeImage = result.getImage(); @@ -1044,6 +1047,9 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette configuredProjectRes, frameworkResources, mProjectCallback, mLogger); + // post-rendering clean up + bridge.cleanUp(); + // update the UiElementNode with the layout info. if (result.getSuccess() == ILayoutResult.SUCCESS) { model.setEditData(result.getImage()); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java index fbfea5949..591282b8c 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java @@ -1085,6 +1085,9 @@ public class GraphicalEditorPart extends EditorPart configuredProjectRes, frameworkResources, mProjectCallback, mLogger); + // post rendering clean up + bridge.cleanUp(); + mCanvasViewer.getCanvas().setResult(result); // update the UiElementNode with the layout info. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java index abd7cf823..dd1f05423 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetData.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.adt.internal.sdk; +import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider; import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors; import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.AndroidManifestDescriptors; @@ -28,6 +29,7 @@ import com.android.layoutlib.api.ILayoutBridge; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.IAndroidTarget.IOptionalLibrary; +import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Hashtable; import java.util.Map; @@ -55,6 +57,27 @@ public class AndroidTargetData { public ClassLoader classLoader; public int apiLevel; + + /** + * Post rendering clean-up that must be done here so that it's done even for older + * versions of the layoutlib. + */ + public void cleanUp() { + try { + Class looperClass = classLoader.loadClass("android.os.Looper"); //$NON-NLS-1$ + Field threadLocalField = looperClass.getField("sThreadLocal"); //$NON-NLS-1$ + if (threadLocalField != null) { + threadLocalField.setAccessible(true); + // get object. Field is static so no need to pass an object + ThreadLocal threadLocal = (ThreadLocal) threadLocalField.get(null); + if (threadLocal != null) { + threadLocal.remove(); + } + } + } catch (Exception e) { + AdtPlugin.log(e, "Failed to clean up bridge for API level %d", apiLevel); + } + } } private final IAndroidTarget mTarget; diff --git a/eclipse/sites/external/.gitignore b/eclipse/sites/external/.gitignore new file mode 100644 index 000000000..ccfee1d0a --- /dev/null +++ b/eclipse/sites/external/.gitignore @@ -0,0 +1,2 @@ +*.jar +*/*.jar \ No newline at end of file