Skip to content

Commit

Permalink
[Mono.Android] Dispose of the RunnableImplementor on error (#8907)
Browse files Browse the repository at this point in the history
Context: 3ce27c9

Commit 3ce27c9 had a TODO:

> TODO: Address [^0] and dispose of the `RunnableImplementor` instance
> when `View.Post()` returns `false`.
>
> [^0]: we leak if `View.post(Runnable)` returns *false*.

The time is now!  Review all `new RunnableImplementor(…, true)` calls,
and if a "removable" `RunnableImplementor` is passed to a method
which can return an error such as [`Handler.post()`][0] or
[`View.post()`][1], dispose of the `RunnableImplementor` instance
on error.

[0]: https://developer.android.com/reference/android/os/Handler#post(java.lang.Runnable)
[1]: https://developer.android.com/reference/android/view/View#post(java.lang.Runnable)
  • Loading branch information
jonpryor authored May 6, 2024
1 parent d25f3de commit 0781fac
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 7 deletions.
35 changes: 30 additions & 5 deletions src/Mono.Android/Android.OS/Handler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,52 @@ public Handler (Action<Message> handler)

public bool Post (Action action)
{
return Post (new Java.Lang.Thread.RunnableImplementor (action, true));
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
if (Post (runnable)) {
return true;
}
runnable.Dispose ();
return false;
}

public bool PostAtFrontOfQueue (Action action)
{
return PostAtFrontOfQueue (new Java.Lang.Thread.RunnableImplementor (action, true));
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
if (PostAtFrontOfQueue (runnable)) {
return true;
}
runnable.Dispose ();
return false;
}

public bool PostAtTime (Action action, long uptimeMillis)
{
return PostAtTime (new Java.Lang.Thread.RunnableImplementor (action, true), uptimeMillis);
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
if (PostAtTime (runnable, uptimeMillis)) {
return true;
}
runnable.Dispose ();
return false;
}

public bool PostAtTime (Action action, Java.Lang.Object token, long uptimeMillis)
{
return PostAtTime (new Java.Lang.Thread.RunnableImplementor (action, true), token, uptimeMillis);
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
if (PostAtTime (runnable, token, uptimeMillis)) {
return true;
}
runnable.Dispose ();
return false;
}

public bool PostDelayed (Action action, long delayMillis)
{
return PostDelayed (new Java.Lang.Thread.RunnableImplementor (action, true), delayMillis);
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
if (PostDelayed (runnable, delayMillis)) {
return true;
}
runnable.Dispose ();
return false;
}

public void RemoveCallbacks (Action action)
Expand Down
14 changes: 12 additions & 2 deletions src/Mono.Android/Android.Views/View.cs
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,22 @@ public T RequireViewById<

public bool Post (Action action)
{
return Post (new Java.Lang.Thread.RunnableImplementor (action, true));
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
if (Post (runnable)) {
return true;
}
runnable.Dispose ();
return false;
}

public bool PostDelayed (Action action, long delayMillis)
{
return PostDelayed (new Java.Lang.Thread.RunnableImplementor (action, true), delayMillis);
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
if (PostDelayed (runnable, delayMillis)) {
return true;
}
runnable.Dispose ();
return false;
}

public bool RemoveCallbacks (Action action)
Expand Down

0 comments on commit 0781fac

Please sign in to comment.