Skip to content

Commit 0781fac

Browse files
authored
[Mono.Android] Dispose of the RunnableImplementor on error (#8907)
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)
1 parent d25f3de commit 0781fac

File tree

2 files changed

+42
-7
lines changed

2 files changed

+42
-7
lines changed

src/Mono.Android/Android.OS/Handler.cs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,52 @@ public Handler (Action<Message> handler)
1313

1414
public bool Post (Action action)
1515
{
16-
return Post (new Java.Lang.Thread.RunnableImplementor (action, true));
16+
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
17+
if (Post (runnable)) {
18+
return true;
19+
}
20+
runnable.Dispose ();
21+
return false;
1722
}
1823

1924
public bool PostAtFrontOfQueue (Action action)
2025
{
21-
return PostAtFrontOfQueue (new Java.Lang.Thread.RunnableImplementor (action, true));
26+
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
27+
if (PostAtFrontOfQueue (runnable)) {
28+
return true;
29+
}
30+
runnable.Dispose ();
31+
return false;
2232
}
2333

2434
public bool PostAtTime (Action action, long uptimeMillis)
2535
{
26-
return PostAtTime (new Java.Lang.Thread.RunnableImplementor (action, true), uptimeMillis);
36+
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
37+
if (PostAtTime (runnable, uptimeMillis)) {
38+
return true;
39+
}
40+
runnable.Dispose ();
41+
return false;
2742
}
2843

2944
public bool PostAtTime (Action action, Java.Lang.Object token, long uptimeMillis)
3045
{
31-
return PostAtTime (new Java.Lang.Thread.RunnableImplementor (action, true), token, uptimeMillis);
46+
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
47+
if (PostAtTime (runnable, token, uptimeMillis)) {
48+
return true;
49+
}
50+
runnable.Dispose ();
51+
return false;
3252
}
3353

3454
public bool PostDelayed (Action action, long delayMillis)
3555
{
36-
return PostDelayed (new Java.Lang.Thread.RunnableImplementor (action, true), delayMillis);
56+
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
57+
if (PostDelayed (runnable, delayMillis)) {
58+
return true;
59+
}
60+
runnable.Dispose ();
61+
return false;
3762
}
3863

3964
public void RemoveCallbacks (Action action)

src/Mono.Android/Android.Views/View.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,22 @@ public T RequireViewById<
4949

5050
public bool Post (Action action)
5151
{
52-
return Post (new Java.Lang.Thread.RunnableImplementor (action, true));
52+
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
53+
if (Post (runnable)) {
54+
return true;
55+
}
56+
runnable.Dispose ();
57+
return false;
5358
}
5459

5560
public bool PostDelayed (Action action, long delayMillis)
5661
{
57-
return PostDelayed (new Java.Lang.Thread.RunnableImplementor (action, true), delayMillis);
62+
var runnable = new Java.Lang.Thread.RunnableImplementor (action, removable: true);
63+
if (PostDelayed (runnable, delayMillis)) {
64+
return true;
65+
}
66+
runnable.Dispose ();
67+
return false;
5868
}
5969

6070
public bool RemoveCallbacks (Action action)

0 commit comments

Comments
 (0)