OSDN Git Service

Fix Canvas memory leak
authorDiego Perez <diegoperez@google.com>
Mon, 1 Feb 2016 11:48:16 +0000 (11:48 +0000)
committerDiego Perez <diegoperez@google.com>
Fri, 19 Feb 2016 17:57:36 +0000 (17:57 +0000)
Every RenderSession would call the AttachInfo.setAttachInfo but wouldn't
issue a View.dispatchDetachedFromWindow.
This caused some Canvas to be slowly leaked in the DelegateManager in
every session.

Change-Id: I0322767e5fffc6053ce1be852dd8ca904dfaa137

tools/layoutlib/bridge/src/android/view/AttachInfo_Accessor.java
tools/layoutlib/bridge/src/android/view/ViewRootImpl_RunQueue_Delegate.java [new file with mode: 0644]
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java

index 4901f72..94f3f54 100644 (file)
@@ -45,4 +45,10 @@ public class AttachInfo_Accessor {
     public static void dispatchOnPreDraw(View view) {
         view.mAttachInfo.mTreeObserver.dispatchOnPreDraw();
     }
+
+    public static void detachFromWindow(View view) {
+        if (view != null) {
+            view.dispatchDetachedFromWindow();
+        }
+    }
 }
diff --git a/tools/layoutlib/bridge/src/android/view/ViewRootImpl_RunQueue_Delegate.java b/tools/layoutlib/bridge/src/android/view/ViewRootImpl_RunQueue_Delegate.java
new file mode 100644 (file)
index 0000000..51b42a6
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * 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 the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of
+ * {@link ViewRootImpl.RunQueue}
+ *
+ * Through the layoutlib_create tool, the original  methods of ViewRootImpl.RunQueue have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ */
+public class ViewRootImpl_RunQueue_Delegate {
+
+    @LayoutlibDelegate
+    /*package*/ static void postDelayed(ViewRootImpl.RunQueue thisQueue, Runnable action, long
+            delayMillis) {
+        // The actual RunQueue is never run and therefore never cleared. This method avoids
+        // runnables to be added to the RunQueue so they do not leak resources.
+    }
+}
index 2ac212c..fea633e 100644 (file)
@@ -208,6 +208,9 @@ public class BridgeRenderSession extends RenderSession {
 
     @Override
     public void dispose() {
+        if (mSession != null) {
+            mSession.dispose();
+        }
     }
 
     /*package*/ BridgeRenderSession(RenderSessionImpl scene, Result lastResult) {
index ec50cfe..99af226 100644 (file)
@@ -1396,4 +1396,21 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
     public RenderSession getSession() {
         return mScene;
     }
+
+    public void dispose() {
+        AttachInfo_Accessor.detachFromWindow(mViewRoot);
+        if (mCanvas != null) {
+            mCanvas.release();
+            mCanvas = null;
+        }
+        if (mViewInfoList != null) {
+            mViewInfoList.clear();
+        }
+        if (mSystemViewInfoList != null) {
+            mSystemViewInfoList.clear();
+        }
+        mImage = null;
+        mViewRoot = null;
+        mContentRoot = null;
+    }
 }
index fe16a3e..6b23da7 100644 (file)
@@ -291,7 +291,6 @@ public class Main {
     @Test
     public void testActivity() throws ClassNotFoundException {
         renderAndVerify("activity.xml", "activity.png");
-
     }
 
     /** Test allwidgets.xml */
@@ -431,6 +430,8 @@ public class Main {
             ImageUtils.requireSimilar(goldenImagePath, session.getImage());
         } catch (IOException e) {
             getLogger().error(e, e.getMessage());
+        } finally {
+            session.dispose();
         }
     }
 
index cb84a1b..79a9a6f 100644 (file)
@@ -185,6 +185,7 @@ public final class CreateInfo implements ICreateInfo {
         "android.view.View#getWindowToken",
         "android.view.View#isInEditMode",
         "android.view.ViewRootImpl#isInTouchMode",
+        "android.view.ViewRootImpl$RunQueue#postDelayed",
         "android.view.WindowManagerGlobal#getWindowManagerService",
         "android.view.inputmethod.InputMethodManager#getInstance",
         "android.view.MenuInflater#registerMenu",