Do I need to unsubscribe Click event to prevent memory leaks? - c#

I am learning Xamarin Android, and I see a lot of official samples using lambdas to subscribe Click events. Something like: mButton.Click += (sender, args) => { ... } is very common. I think this pattern, using lambda, cannot unsubscribe the event.(Correct me if I am wrong :) )
Today I read this document: Cross-Platform Performance - Unsubscribe from Events. It says that we should unsubscribe events to prevent memory leaks.
Then I am confused. Should I unsubscribe all the Click events? I feel that since the mButton is a member of my Activity, when destroying my Activity, the mButton should also be destroyed and therefore it is not necessary to unsubscribe its Click event. Is is true? If so, then in what cases should I unsubscribe a event?
Thanks!

I would say it depends. As long there there are no references kept and the garbage collector can do his job, you don't have to. But otherwise it is good practice to do so to prevent memory leaks. So I prefer doing this.
To unsibscribe lambda events, just store it in a variable or field
EventHandler buttonOnClick = (sender, args) => button.Text = string.Format("{0} clicks!", count++);
button.Click += buttonOnClick;
button.Click -= buttonOnClick;

This is how I generally do it
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.LoginPage);
InflateViews ();
}
protected override void OnResume ()
{
base.OnResume ();
BindHandlers ();
}
protected override void OnPause ()
{
base.OnPause ();
UnBindHandlers ();
}
void InflateViews()
{
loginButton = FindViewById (Resource.Id.loginButton);
usernameField = FindViewById<EditText> (Resource.Id.userName);
passwordField = FindViewById<EditText> (Resource.Id.password);
forgotPassword = FindViewById (Resource.Id.forgotPassword);
}
void BindHandlers()
{
loginButton.Click+= LoginButton_Click;
forgotPassword.Click+= ForgotPassword_Click;
}
void ForgotPassword_Click (object sender, EventArgs e)
{
StartActivity (typeof(ForgotPasswordActivity));
}
void UnBindHandlers()
{
loginButton.Click-= LoginButton_Click;
forgotPassword.Click-= ForgotPassword_Click;
}

Absolutely yes!
To prevent memory leaks it is important to prevent cycling references and such. Take your time and search on SO and you will find a lot about this topic.

Related

How to remove ViewTreeObserver in Xamarin?

Let's just say I need to get and set a View's height. In Android, it's known you can get a view height only after it's drawn. If you're using Java, many answers, one of the most well-known way is like this one below, taken from this answer:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
view.getHeight(); //height is ready
}
});
Thus I search C#/Xamarin version, and found this works:
int viewHeight = 0;
ViewTreeObserver vto = view.ViewTreeObserver;
vto.GlobalLayout += (sender, args) =>
{
viewHeight = view.Height;
};
Thing is, it fired again and again. In Java version, it can be removed with
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
How to do it in C#\Xamarin? Should I resort to using boolean properties to know whether it's executed or not? Is there not way to do it like the android one?
If you are using C# Events, avoid using anonymous events if you need to unsubscribe, or you can implement the IOnGlobalLayoutListener and add/remove the listener:
C# EventHandler Style:
Create an EventHandler method for the event to invoke:
void Globallayout_handler(object sender, EventArgs e)
{
// ViewTreeObserver.IOnGlobalLayoutListener events
}
Subscribe:
var viewTreeObserver = aView.ViewTreeObserver;
viewTreeObserver.GlobalLayout += Globallayout_handler;
Unsubscribe:
var viewTreeObserver = aView.ViewTreeObserver;
viewTreeObserver.GlobalLayout -= Globallayout_handler;
Java Listener Style in C#:
Add and implement ViewTreeObserver.IOnGlobalLayoutListener:
public class CustomButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer,
ViewTreeObserver.IOnGlobalLayoutListener
{
~~~~
public void OnGlobalLayout()
{
// ViewTreeObserver.IOnGlobalLayoutListener events
}
}
Now you can use the Java way to add and remove this listener:
aView.ViewTreeObserver.RemoveOnGlobalLayoutListener(this);
aView.ViewTreeObserver.AddOnGlobalLayoutListener(this);
Even though the answer given by ShshiHangover is correct in principle, the unsubscribing didn't work for me as expected (using the regular method #1).
The reason is probably that the ViewTreeObserver in the called method can be different from the one the event handler subscribed to, so removing it may not work (i.e., the handler method is called continuously).
The correct way of doing this is to unsubscribe from the event sender object while ensuring that IsAlive yields true:
void ViewTreeObserver_GlobalLayout(object sender, EventArgs e)
{
ViewTreeObserver vto = (ViewTreeObserver)sender;
if (vto.IsAlive) {
vto.GlobalLayout -= ViewTreeObserver_GlobalLayout;
}
}
Neither #Daniel or #SushiHangover methods would actually unsubscribe for me (maybe an sdk bug?). My only solution was to set a bool flag on first run. It would be nice to know how to actually unsubscribe however...
Getting the ViewTreeObserver via sender never seems to be IsAlive whereas getting the tree from the View does. However either way the event doesn't get properly removed.
private void Setup()
{
cameraView = FindViewById<SurfaceView>(Resource.Id.camera_view);
//need to wait for view to inflate to get size
isSetup = false;
ViewTreeObserver vto = cameraView.ViewTreeObserver;
vto.GlobalLayout += Vto_GlobalLayout;
}
void Vto_GlobalLayout(object sender, System.EventArgs e)
{
//this didn't work either
//ViewTreeObserver vto = cameraView.ViewTreeObserver;
//vto.GlobalLayout -= Vto_GlobalLayout;
ViewTreeObserver vto = (ViewTreeObserver)sender;
if (vto.IsAlive)
vto.GlobalLayout -= Vto_GlobalLayout; //even after removing it seems to continue to fire...
if (!isSetup)
{
isSetup = true;
DoYourCodeNow();
}
}

Best option for event subscription

Can you tell me which is the best way to create an event or all the options are good?
// OPTION 1
buttonAlert.Click += delegate
{
textChange.Text = string.Format("Hello World");
};
// OPTION 2
buttonAlert.Click +=(sender, e) =>
{
textChange.Text = string.Format("Hello World");
};
// OPTION 3
buttonAlert.Click += delegate (object sender, EventArgs e)
{
textChange.Text = string.Format("Hello World");
};
Its just a matter of preference. In terms of performance are all equivalent.
So, choose based on what you need and prefer.
As a complement of my answer i like to alert that you must unsubscribe a event (-=) after subscrive (+=).
From the documentation:
To prevent your event handler from being invoked when the event is
raised, simply unsubscribe from the event. In order to prevent
resource leaks, it is important to unsubscribe from events before you
dispose of a subscriber object. Until you unsubscribe from an event,
the multicast delegate that underlies the event in the publishing
object has a reference to the delegate that encapsulates the
subscriber's event handler. As long as the publishing object holds
that reference, your subscriber object will not be garbage collected.
I would say that first option is the best when you don´t need the lambda parameters (sender, event).
Between second and third I would choose second because it´s cleaner (just a matter of preference.
You can also use a method as a delegate, and it´s probably the best if you want to manage memory correctly. When you use a delegate or lambda there is no way to unsubscribe. That means that even if you destroy or leave the activity/fragment, the object will remain in memory and the garbage collector won´t be able to clear it. In the case the user opens and closes this screen many times, you may get an OutOfMemoryException eventually. This happens very often in Android. This would be the solution:
protected override void OnResume()
{
base.OnResume();
buttonAlert.Click += OnButtonClick;
}
protected override void OnPause()
{
base.OnPause();
buttonAlert.Click -= OnButtonClick;
}
private void OnButtonClick(object sender, EventArgs e)
{
textChange.Text = string.Format("Hello World");
}

Will this usage of event lead to memory leak in silverlight?

I'm wondering if this usage of events will cause memory leaks in Silverlight?
private void Button_Click(object sender, RoutedEventArgs e)
{
var test = new ChildWindow();
EventHandler closedEvent = null;
closedEvent =
(s, args) =>
{
test.Closed -= closedEvent;
if (test.DialogResult == true)
{
// something
}
};
test.Closed += closedEvent;
test.Show();
}
I have dozen sample usage of Closed event which are left wired and leaky. Just wondered if this sample would eliminate the memory leak?
Thanks.
I don`t see any reason for memory leak. On every button click u allocate new ChildWindow object, which will be garbaged after method ended, coz you not store reference.
Labda (its object too) will be garbaged after the ChildWindow object.

How do I Unregister 'anonymous' event handler [duplicate]

This question already has answers here:
Unsubscribe anonymous method in C#
(14 answers)
Closed 8 years ago.
Say if I listen for an event:
Subject.NewEvent += delegate(object sender, NewEventArgs e)
{
//some code
});
Now how do I un-register this event? Or just allow the memory to leak?
Give your instance of the anonymous delegate a name:
EventHandler<NewEventArg> handler = delegate(object sender, NewEventArgs e)
{
//some code
};
Subject.NewEvent += handler;
Subject.NewEvent -= handler;
If you need to unregister an event, I recommend avoiding anonymous delegates for the event handler.
This is one case where assigning this to a local method is better - you can unsubscribe from the event cleanly.
To remove the handler on first invocation:
//SubjectType Subject = ..... already defined if using (2)
EventHandler handler = null;
handler = delegate(object sender, EventArgs e)
{
// (1)
(sender as SubjectType).NewEvent -= handler;
// or
// (2) Subject.NewEvent -= handler;
// do stuff here
};
Subject.NewEvent += handler;
You can create method for unregistering from all listeners of event. This not exactly what you whant, but sometimes it can be helpfull. For example (this really works =)) :
class Program {
static void Main(string[] args) {
A someClass = new A();
someClass.SomeEvent += delegate(object sender, EventArgs e) {
throw new NotImplementedException();
};
someClass.ClearEventHandlers();
someClass.FireEvent();
Console.WriteLine("No error.");
}
public class A {
public event EventHandler SomeEvent;
public void ClearEventHandlers() {
Delegate[] delegates = SomeEvent.GetInvocationList();
foreach (Delegate delegate in delegates) {
SomeEvent -= (EventHandler) delegate;
}
}
public void FireEvent() {
if (SomeEvent != null) {
SomeEvent(null, null);
}
}
}
}
You need a name for your anonymous function, and then, you can only do it as long as the name is in scope:
var handler = new EventHandler(delegate(object o, EventArgs e)
{
//do something...
};
Subject.NewEvent += handler;
// later on while handler is still in scope...
Subject.NewEvent -= handler;
Do you need to un-register it for a reason other than leakage?
Regarding the "Or just allow the memory to leak" bit, when Subject is cleaned up by the Garbage Collector, your anonymous delegate should be cleaned up as well, so there shouldn't be a leak.
There is another question (of mine) which goes into this in some (too much) detail: Weak event handler model for use with lambdas.
However, now that the Reactive Framework has come out, I'd seriously consider looking into that in this kind of situation.

.NET: Is creating new EventArgs every time the event fires a good practice?

For example, I have a base event publishing method:
protected virtual OnSomeEvent(EventArgs e)
{
var handler = SomeEvent;
if (handler != null)
{
handler(this, e);
// handler(this, new EventArgs());// EDIT: Yes it should be
// handler(this, e),
// ignore this one :D
}
}
For a derived class that overrides OnSomeEvent and raises an additional event when it fires:
protected override OnSomeEvent(EventArgs e)
{
base.OnSomeEvent(e);
if (ExtendedEvent != null)
{
OnExtendedEvent(e);
}
}
protected void OnExtendedEvent(EventArgs e)
{
// some stuff done
// new information the ExtendedEventArgs object needs
// is not available until this point
ExtendedEvent(this, new ExtendedEventArgs(someStuff, someOtherStuff));
}
And if derivation goes on like this, it will create a new derived EventArgs for each generation of derived class that requires it. However it seems various derivations of EventArgs on the .NET framework are not designed to be mutable (no setters), this discourages an object from keeping a single instance of EventArgs and modify it as it goes.
So every time an event like this fires, it will re-allocate memory for all involved EventArgs objects. In a graphic intense application where an event can be triggered dozens of times per second (such as OnPaint event on a control), is this really a good practice?
Should I make some changes to OnExtendedEvent() and make ExtendedEventArgs mutable so the following is possible?
protected ExtendedEventArgs extendedArgs = ExtendedEventArgs.Empty;
protected void OnExtendedEvent(EventArgs e)
{
// some stuff done
// new information the ExtendedEventArgs object needs
// is not available until this point
extendedArgs.someProperty1 = someStuff;
extendedArgs.someProperty2 = someOtherStuff;
ExtendedEvent(this, extendedArgs);
}
EDIT: Fixed the example code, should be clearer now.
First off, why take an EventArgs argument to your firing method if you are just ignoring it anyway? That is the real waste, but the resource consumption is less problematic than the lie that your method is telling its callers. Just pass the argument on through, your firing method likely will not have relevant info accessible to create the EventArgs object anyway:
protected virtual OnSomeEvent(EventArgs e)
{
var handler = SomeEvent;
if (handler != null)
{
handler(this, e);
}
}
So, now that we have that straight, if your EventArgs object has no meaningful information to tell your subscribers, just use EventArgs.Empty, that's what it is there for. You could follow the same pattern for your custom EventArgs classes, but honestly, you are worrying about nothing. Creating EventArgs objects will never be a bottleneck in your application, and if it is, you have design problems.
I would create a new immutable object each time it is fired, as there are values in the event arguments.
The main reason is the what would happen if a new event is fired again while an existing event is being handled?
This will possibly happen in multi-threaded applications but may even happen on a single thread as shown by the following example:
First event is fired with the following values:
extendedArgs.someProperty1 = "Fire 1";
extendedArgs.someProperty2 = "Fire 1 Other Stuff";
Then somehow the first event handler does something causes the event to be fired again with the following arguments:
extendedArgs.someProperty1 = "Fire 2";
extendedArgs.someProperty2 = "Fire 2 Other Stuff";
All the event handlers are for the second event are processed, and now we are back to processing the rest of the event handlers for the first event.
Now since the same object is used all the event handlers for the first event will now be have "Fire 2" as their someProperty1, as the second event overwrote the values.
As #nobugz mentioned don't be afraid to create short-lived garbage.
I'm a little confused by your OnExtendedEvent code - are you meaning to redispatch the event as a SomeEvent?
When a client adds an event handler, they expect they are able to remove the event handler while handling the event, like this:
someObject.SomeEvent += OnSomeEvent;
// ...
private void OnSomeEvent(object sender, EventArgs e)
{
someObject.SomeEvent -= OnSomeEvent;
}
If you do not follow the standard dispatching practice, this code will throw an Exception very much to the surprise of the person using your code.

Categories