How do I Remove Button Listeners - and should I?

Hello World!

I have added a Button Listener when my script is Awake:

void Awake() {

settingsButton1.onClick.AddListener(() => PlayMusicTrack());

}

Then I (should?) disable the listener here:

private void OnDisable() {

Debug.Log(“remove listener”);

}

Should I? And how should I do it using RemoveListener?

Newbie in training says: THANK YOU!

1 Like

I’m assuming that every time I open the settings and this script becomes ‘Active’, another Listener get’s piled up. But I could be wrong. I’m hoping I don’t have garbage collecting in my scripts. =P

Please consider using code tags in future.

Anyway, if both the button and the subscriber are leaving the scene/being destroed at the same time (such as a scene being unloaded or exiting playmode), then it shouldn’t be a problem.

If the subscriber is leaving/destroyed while the button remains, then it should unsubscribe, same as with any delegate.

Also you don’t need to do this:

settingsButton1.onClick.AddListener(() => PlayMusicTrack());

There’s no point doing an anonymous method when you’re only using it to call a parameterless method. You can just do:

settingsButton1.onClick.AddListener(PlayMusicTrack);

Then you can just RemoveListener(PlayMusicTrack); to unsubscribe.

2 Likes

Okay, I just saw how to do that (use code tag), as per your instruction. =)

I should have used this example as it actually is applied to Next and Previous buttons which navigate through Sound Tracks:

next.onClick.AddListener(() => Select(1));
previous.onClick.AddListener(() => Select(-1));

The UI page gets hidden and unhidden (active, inactive) as needed while navigating the UI.
Each time it is ‘awake’ it adds the listeners.
I just wanted to make sure they aren’t sticking around and piling up.

So I thought maybe it would look something like this:

private void OnDisable()
{
    next.onClick.RemoveAllListeners();
    previous.onClick.RemoveAllListeners();
}

If you keep adding listeners without removing them, yes I believe they will continue to pile up causing unexpected behaviour.

Like any delegate you need to unsubscribe when needed, otherwise you’ll get unexpected behaviour, or null-reference errors if the listener no longer exists.

1 Like

Awesome, then I think I will add the code in OnDisable() as I wrote above.
Only thing I will change is:
Instead of adding the listeners on Awake(), I’ll be adding them OnEnable().
So my final result looks like this:

    private void OnEnable()
    {
        next.onClick.AddListener(() => Select(1));
        previous.onClick.AddListener(() => Select(-1));
    }

    private void OnDisable()
    {
        next.onClick.RemoveAllListeners();
        previous.onClick.RemoveAllListeners();
    }

So far I have only asked a couple questions on here, and you’ve been very helpful each time.
Thanks Spiney199!

That’s the pattern I use, never had any issues with it: OnEnable / OnDisable is solid for MonoBehaviours.

I think it’s just Good Practice™ doing the remove as well: you never know if years down the line you’ll change the behaviour or lifecycle slightly and violate your “add once” assumptions.

2 Likes

As a rule, I would avoid using RemoveAllListeners when in effect you are trying to remove one listener. This is a good way for obfuscated bugs to occur. Instead, I’d format this using methods that I can directly put into the appropriate method:

private void SelectNext () {
  Select(1);
}

private void SelectPrevious () {
  Select(-1);
}

private void OnDisable () {
  next.onClick.RemoveListener(SelectNext);
  next.onClick.RemoveListener(SelectPrevious);
}

private void OnEnable () {
  next.onClick.AddListener(SelectNext);
  next.onClick.AddListener(SelectPrevious);
}
2 Likes

:sunglasses: TY

I just like to add. OnEnable and OnDisable are the respective counterparts as it was already established in this thread. The counterpart of Awake is OnDestroy. So don’t mix them up :slight_smile: OnEnable / OnDisable are called every time the gameobject / component changes its activated / enabled state. Awake and OnDestroy are one time events in the lifetime of the object. Awake will only be called once and so is OnDestroy. So things done in Awake that needs to be “undone” have to be reverted in OnDestroy. Though, especially when it comes to event subscriptions using OnEnable / OnDisable usually makes more sense as in 99% of all cases you would expect a component to not react to events when you disable it. Though there are always exceptions of course :slight_smile:

1 Like