Mediating a non-displayObject
Hey guys,
I am trying to determine the best way to mediate a
non-displayObject and would like to ask for some ideas/feedback. I
have a class "MediaPlayer" which is a controller in my application,
and it extends another base class. I want this object to be able to
listen for context events, and dispatch events into the context. My
initial thought was that I would just mediate it (i.e. map it to
"MediaPlayerMediator"), then wire up the mediator to listen for
events from the context and the "view" and handle things as a
normal mediator would. The issue is that MediaPlayer (being a
controller) never gets added to the displaylist, so the onRegister
event never fires off. I looked at simply extending Actor; however,
I am already extending another base class, so this is not really
practical (I would need to change a decent piece of my architecture
to make this work). I realize that the MediaPlayer object is not
technically something that should be mediated since it is not a
view, but this seems to make the most sense to me in terms of its'
uses and desired functionality.
Can anyone suggest a good way to handle this type of situation?
Thanks!
-Kyle
Comments are currently closed for this discussion. You can start a new one.
2 Posted by Stray on 17 Sep, 2011 10:45 PM
Rather than extending Actor, make your MediaPlayer a property of an Actor - then you can use the Actor just as you would use a mediator - to relay events back and forth. The only difference is that you'll need to use a [postConstruct] tag on your own 'onRegister' function. You even get access to an eventMap in the Actor class - so in all other respects it's very similar.
hth,
Stray
Support Staff 3 Posted by Till Schneidereit on 17 Sep, 2011 10:50 PM
Hi Kyle,
you can access the context's event bus by simply adding an injection for it:
[Inject] public var eventBus : IEventDispatcher;
Then you need to construct the MediaPlayer using the injector, or use
injector.injectInto(mediaPlayerInstance);
Depending on how exactly your MediaPlayer is used, you might also
consider not making it listen to application events itself. Instead,
you could make it available for injection and map commands to the
events of interest. In these commands, you inject the MediaPlayer and
invoke the desired functionality through a public API. That way, your
MediaPlayer would behave pretty similarly to a model, from an
application architecture point of view.
cheers,
till
4 Posted by Kyle on 18 Sep, 2011 03:54 PM
Hey Stray,
The reason I wanted to use inheritance for my mediaPlayer is so I could have direct access to the public API provided by the parent class. By making it a public property of an actor, I would lose this direct access to the API. It is a bit of a strange scenario I suppose. I'd like the mediaPlayer to respond to context events, dispatch events back into the context, but also allow for direct access so that commands can make calls to its' API. Does that make sense at all, or am I trying to cross two different development paths here?
To explain a bit further:
At startup, a command fires off that creates the MediaPlayer instance, then stores it in a model. When, for example, a play event gets fired off from another actor in the application, I'd like to be able to have the MediaPlayer respond directly to the event, calling it's own play() method. Alternately, I'd like a command to also be able to access the model, get reference to the MediaPlayer instance, then calls methods on it (i.e. model.mediaPlayer.play() ).
I'd prefer not to solely have to use commands as I would have to create a LOT of commands to map all of these properties, and it seems a bit overkill as all the commands would do is essentially proxy the event to the MediaPlayer.
Any further thoughts are appreciated as always!
-Kyle
5 Posted by Kyle on 18 Sep, 2011 03:57 PM
Hey Till,
Thanks for the response! Can you please check out my response to Stray above (explains the scenario a bit more )?
Basically though, at startup, a command fires off that creates the MediaPlayer instance, then stores it in a model. So the MediaPlayer object can then be accessed by commands that inject the model, alternately, however, I'd like to be able to have the MediaPlayer listen for and dispatch commands (mostly to save myself having to create a ton of commands).
Thanks!
-Kyle
6 Posted by Stray on 18 Sep, 2011 04:14 PM
Hi Kyle,
I don't see how you would lose access to the API - the Actor would simply act as a mediator for your class - responding to events as you described.
Have another think, and if you need a step-by-step of how to implement it then some sample code we can spin off from would be useful :)
Stray
Support Staff 7 Posted by Till Schneidereit on 18 Sep, 2011 04:18 PM
Hi Kyle,
just as Stray, I don't see a fundamental problem with using an actor
as sort of a mediator.
But again: If you want to directly expose the event bus to your
MediaPlayer, you can always do that by injecting it into the player.
Or, you can of course also set it manually during instantiation.
8 Posted by Kyle on 18 Sep, 2011 05:04 PM
Hey guys,
Thanks for the info. I think that extending Actor makes sense, I'm just a bit confused on how exactly to go about this implementation. I extend Actor, but how/where/when do I go about adding my listeners (i.e. at what point do I know I have access to the event bus)? Also, how do I go about dispatching events back out into the context?
Thanks!
-Kyle
9 Posted by Stray on 18 Sep, 2011 05:10 PM
Hi Kyle,
You can use the [postConstruct] tag on any public function, and it will run as soon as the eventDispatcher (and any other injections such as your mediaPlayer) has been injected.
So - make your own onRegister function, tag it with [postConstruct] and away you go...
Then use the eventMap property of the Actor, just exactly as you would with the mediator. In essence it's identical.
Stray
10 Posted by Kyle on 18 Sep, 2011 05:15 PM
That is just plain sexy! haha! I'll give it a go, but that sounds like it should work perfectly!
11 Posted by Kyle on 18 Sep, 2011 05:37 PM
OK guys,
So below I've pasted a a basic outline of my class.
// START //
public class MyMediaPlayer extends Actor
{
[Inject]
public var eventBus:IEventDispatcher;
public var mediaPlayer:MediaPlayer;
public function MinexaMediaPlayer()
{
super();
mediaPlayer = new MediaPlayer();
}
[postConstruct]
private function onRegister():void
{
// MEDIAPLAYER LISTENERS
mediaPlayer.addEventListener(PlaybackEvent.PLAY, handlePlaybackEvent);
// CONTEXT LISTENERS
eventMap.mapListener( eventBus, MyCustomContextEvent.MY_EVENT, handleMyCustomContextEvent);
}
}
// END //
I think the structure is solid, the only piece I'm not sure of is how to go about injecting the MyMediaPlayer instance into the context. I've tried using the following (per Till's suggestion):
// START //
injector.injectInto( myMediaPlayer );
// END //
The onRegister() method that I've marked with [postConstruct] doesn't seem to fire though..
I'm sure there's something simple I'm missing here...
Thanks!
-Kyle
Support Staff 12 Posted by Till Schneidereit on 18 Sep, 2011 06:04 PM
Hey Kyle,
you've almost everything right. The only problem that's left is that
metadata iscase-sensitive, so it has to be [PostConstruct], with an
upper "P".
Also, note that when extending actor, you don't need to inject the
eventBus - it's already injected into the base-class:
https://github.com/robotlegs/robotlegs-framework/blob/master/src/org/robotlegs/mvcs/Actor.as
Thus, you can listen to framework-events using the event map and
dispatch them using the dispatch method provided by Actor.
cheers,
till
13 Posted by Stray on 18 Sep, 2011 06:14 PM
Oops! Yes, PostConstruct not postConstruct - thanks Till :)
14 Posted by Kyle on 18 Sep, 2011 06:30 PM
Guys,
Thanks so much for all your help! I was able to get things working successfully! One important thing to note:
When using [PostConstruct] (CAPITAL P haha), the method needs to be public in order for the injector to call it. Might be a small gotcha for anyone tryin to implement this.
Also, is the [PostConstruct] and other more advanced framework usage documented somewhere?
Thanks again!
-Kyle
Support Staff 15 Posted by Till Schneidereit on 18 Sep, 2011 06:38 PM
Great to hear that everything's working now.
The [PostConstruct]-method needing to be public is due to restrictions
in AS3's reflection capabilities and there's nothing we can do about
that, unfortunately. The same is true for every other type of metadata
- you just can't get to it for methods in the private or protected
namespace. (In case of PostConstruct, though, it makes sense: The
method really is called from the outside and you'd want to be able to
call it manually during unit testing, for example.)
As for documentation: Metadata-support is provided by Swiftsuspenders,
which has a rather dense README on github:
https://github.com/tschneidereit/SwiftSuspenders/#readme
I know that the documentation is not as accessible as it could be.
Changing that is of high priority for Swiftsuspenders 2.
16 Posted by Abel de Beer on 19 Sep, 2011 01:11 AM
This might also be a nice addition to the discussion: Mediate non-visual view components
17 Posted by Kyle on 19 Sep, 2011 02:44 AM
Great info. in that post as well Stray, thanks!
Kyle closed this discussion on 02 Oct, 2011 09:55 PM.