mediator removal issue
Hi,
I've noticed that there's a delay in removing a Mediator once it's view has been removed and it's REMOVED_FROM_STAGE event has fired.
Up until now i've simply relied on the in built mechanism of the Mediator, to clean up the mapped listeners of their view and this has worked a treat. In simplfied terms, i've now got a situation where one view is removed and another is created, whose mediator then dispatches an event, that's being caught by the old views Mediator, as it's yet to be removed completely.
So the flow is,
ViewA gets destroyed and removed from display list
ViewA fires REMOVED_FROM_STAGE event (if i add a listener directly
to its Mediator, the event is caught immediately)
ViewB is created and added to the display list
ViewB's mediator is created and dispatches an event to set in
motion part of the initialisation of ViewB
ViewA's Mediator catches the result of that event and calls a
function on ViewA
But ViewA has been destroyed so chucks an error
ViewA's Mediator is then destroyed
So the problem i have is due to the fact that the Mediators don't appear to be removed immediately when the REMOVED_FROM_STAGE event of their view is fired and so they're hanging around for a split second (possibly till the next frame?) and as their eventMap has not yet been automatically cleared, they're still receiving and proxying events.
So i realise that i could quite easily add a listener in the Mediator for the views REMOVED_FROM_STAGE event and clean it up myself, but this seems to slightly defeat the point of the simplicity and elegance of the Mediators automatic clean up. Not to mention all the extra code this could potentially create on a larger project. Or am i simply just doing something wrong?
Cheers,
James
Comments are currently closed for this discussion. You can start a new one.
Support Staff 2 Posted by Till Schneidereit on 12 Oct, 2011 10:42 AM
Hi James,
that is an interesting problem - and one that's so obvious that I'm
surprised no-one else seems to have stumbled over it before (including
myself).
The reason for mediators not being removed immediately is that we
can't detect whether a display object is really removed from stage or
only re-parented to another part of the display list. To work around
that, we store the mediators for removed views in a list and only
really remove them in the next frame. If they are only reparented,
they get removed from that list immediately.
I think the best way to work around this would be to set some sort of
flag on the mediator, but that's not too small a change, so we'll
probably not do it for Robotlegs 1, because version 2 should be out in
a couple of months. Therefore, I'd suggest you use the workaround you
described.
hope that helps,
till
3 Posted by james on 12 Oct, 2011 10:54 AM
Hi Till,
thanks a lot for the quick reply.
I've been using RL for over 18 months now and thought exactly the same thing when i came across the problem. It's what made me wonder whether it was something i was doing wrong, as i was surprised i've not come across it before.
I had a poke around in the source and noticed that they're being removed once an ENTER_FRAME is run. Now that you've explained why, that makes complete sense.
The flag sounds like a good idea, as it could just be set when the view and Mediator are mapped if you know the view won't be re-parented.
Thanks again,
James
Support Staff 4 Posted by Till Schneidereit on 12 Oct, 2011 11:03 AM
I've created a ticket in the robotlegs github project so that we don't
forget about the issue. Thanks for bringing it to attention.
5 Posted by james on 12 Oct, 2011 11:09 AM
Nice one, thanks Till. Glad i could be of help, RL really is a pleasure to work with!
This is probably pretty obvious, but i'll post it here just incase anyone else comes across this issue. So much for my rant about extra code...
I've just stuck this line of code in the onRegister method of the offending Mediator,
eventMap.mapListener( view, Event.REMOVED_FROM_STAGE, viewRemovedHandler, Event );Then i simply clear the _eventMap in the handler,
private function viewRemovedHandler( event:Event ):void{
}
Support Staff 6 Posted by Stray on 12 Oct, 2011 11:11 AM
Hi James,
Another quick fix for that specific mediator would be to add a guard clause in your handlers that checks that the view.parent != null.
eg:
Or - you could create a version of the event map to put this clause around your handlers automatically. I'd probably go that route as it's most composition friendly...
To implement that, you'd override your eventMap setter in the mediator:
viewComponent is what the mediator generically uses to refer to your view internally (as a DisplayObject).
Then, you'd just add this check to your special event map (which has stored the viewComponent property that you passed it) - by overriding 'routeEventToListener':
That should be all that is required... if it's a bit befuddling let me know and I can whip it up into a utility on github (with tests) today.
Nice find - we like these corner cases (especially, as Till pointed out, during the pre-release phase for RL2!)
Stray
Support Staff 7 Posted by Stray on 12 Oct, 2011 11:12 AM
Ah... and what you have will work as well!
Stray
8 Posted by james on 12 Oct, 2011 11:27 AM
Thanks Stray, that makes sense and a least i don't have to keep implementing the same logic throughout my offending Mediators.
So just to clarify, i subclass Mediator and override the eventMap accessor and then subclass EventMap and override the routeEventToListener method?
James
9 Posted by james on 12 Oct, 2011 11:54 AM
One last thing, where would be the best place in the EventMap subclass to clean up the reference to the viewComponent? Override unmapListeners() ?
James
10 Posted by Stray on 12 Oct, 2011 12:29 PM
Exactly :)
11 Posted by Stray on 12 Oct, 2011 12:30 PM
Hi James, that shouldn't be necessary - as the eventMap is only a property of the mediator, and the mediator will be GC'd, you should be fine without explicit clean up.
12 Posted by james on 12 Oct, 2011 12:36 PM
Cheers Stray, that's all now up and running. Thanks again for your help.
James
Ondina D.F. closed this discussion on 01 Nov, 2011 05:02 PM.