Dispose handler per-session callbacks Bug: 148785814 Test: all tests should pass Change-Id: I53677ba88aa2aa7b242b59ad7c84746f0ceeef5a
diff --git a/bridge/src/android/os/Handler_Delegate.java b/bridge/src/android/os/Handler_Delegate.java index 4573928..11dfb69 100644 --- a/bridge/src/android/os/Handler_Delegate.java +++ b/bridge/src/android/os/Handler_Delegate.java
@@ -18,9 +18,13 @@ import com.android.ide.common.rendering.api.LayoutLog; import com.android.layoutlib.bridge.Bridge; +import com.android.layoutlib.bridge.android.BridgeContext; +import com.android.layoutlib.bridge.impl.RenderAction; import com.android.layoutlib.bridge.util.HandlerMessageQueue; import com.android.tools.layoutlib.annotations.LayoutlibDelegate; +import java.util.WeakHashMap; + /** * Delegate overriding selected methods of android.os.Handler * @@ -32,7 +36,8 @@ public class Handler_Delegate { // -------- Delegate methods - private static final HandlerMessageQueue sRunnablesQueue = new HandlerMessageQueue(); + private static final WeakHashMap<BridgeContext, HandlerMessageQueue> sRunnablesQueues = + new WeakHashMap<>(); @LayoutlibDelegate /*package*/ static boolean sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) { @@ -42,7 +47,7 @@ callback.sendMessageAtTime(handler, msg, uptimeMillis); } else { if (msg.callback != null) { - sRunnablesQueue.add(handler, uptimeMillis, msg.callback); + currentQueue().add(handler, uptimeMillis, msg.callback); } } return true; @@ -60,7 +65,7 @@ /*package*/ static boolean sendMessageAtFrontOfQueue(Handler handler, Message msg) { // We will also catch calls from the Choreographer that have no callback. if (msg.callback != null) { - sRunnablesQueue.add(handler, 0, msg.callback); + currentQueue().add(handler, 0, msg.callback); } return true; @@ -73,17 +78,18 @@ * @return if there are more callbacks to execute */ public static boolean executeCallbacks() { + HandlerMessageQueue queue = currentQueue(); try { long uptimeMillis = SystemClock_Delegate.uptimeMillis(); Runnable r; - while ((r = sRunnablesQueue.extractFirst(uptimeMillis)) != null) { + while ((r = queue.extractFirst(uptimeMillis)) != null) { r.run(); } } catch (Throwable t) { Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Failed executing Handler callback", t, null, null); } - return sRunnablesQueue.isNotEmpty(); + return queue.isNotEmpty(); } public interface IHandlerCallback { @@ -97,7 +103,12 @@ sCallbacks.set(callback); } - public static void clear() { - sRunnablesQueue.clear(); + public static void dispose(BridgeContext context) { + sRunnablesQueues.remove(context); + } + + private static HandlerMessageQueue currentQueue() { + return sRunnablesQueues.computeIfAbsent(RenderAction.getCurrentContext(), + c -> new HandlerMessageQueue()); } }
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java index 9a48a34..a59a143 100644 --- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java +++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -60,7 +60,7 @@ import android.media.Image; import android.media.Image.Plane; import android.media.ImageReader; -import android.os.Looper; +import android.os.Handler_Delegate; import android.preference.Preference_Delegate; import android.view.AttachInfo_Accessor; import android.view.BridgeInflater; @@ -1189,6 +1189,7 @@ } Choreographer_Delegate.dispose(getContext()); mContentRoot = null; + Handler_Delegate.dispose(getContext()); } catch (Throwable t) { getContext().error("Error while disposing a RenderSession", t); }