Mediating a non-displayObject

Kyle's Avatar

Kyle

17 Sep, 2011 10:16 PM via web

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

  1. 2 Posted by Stray on 17 Sep, 2011 10:45 PM

    Stray's Avatar

    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

  2. Support Staff 3 Posted by Till Schneidereit on 17 Sep, 2011 10:50 PM

    Till Schneidereit's Avatar

    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

  3. 4 Posted by Kyle on 18 Sep, 2011 03:54 PM

    Kyle's Avatar

    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

  4. 5 Posted by Kyle on 18 Sep, 2011 03:57 PM

    Kyle's Avatar

    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

  5. 6 Posted by Stray on 18 Sep, 2011 04:14 PM

    Stray's Avatar

    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

  6. Support Staff 7 Posted by Till Schneidereit on 18 Sep, 2011 04:18 PM

    Till Schneidereit's Avatar

    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.

  7. 8 Posted by Kyle on 18 Sep, 2011 05:04 PM

    Kyle's Avatar

    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

  8. 9 Posted by Stray on 18 Sep, 2011 05:10 PM

    Stray's Avatar

    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

  9. 10 Posted by Kyle on 18 Sep, 2011 05:15 PM

    Kyle's Avatar

    That is just plain sexy! haha! I'll give it a go, but that sounds like it should work perfectly!

  10. 11 Posted by Kyle on 18 Sep, 2011 05:37 PM

    Kyle's Avatar

    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

  11. Support Staff 12 Posted by Till Schneidereit on 18 Sep, 2011 06:04 PM

    Till Schneidereit's Avatar

    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

  12. 13 Posted by Stray on 18 Sep, 2011 06:14 PM

    Stray's Avatar

    Oops! Yes, PostConstruct not postConstruct - thanks Till :)

  13. 14 Posted by Kyle on 18 Sep, 2011 06:30 PM

    Kyle's Avatar

    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

  14. Support Staff 15 Posted by Till Schneidereit on 18 Sep, 2011 06:38 PM

    Till Schneidereit's Avatar

    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.

  15. 16 Posted by Abel de Beer on 19 Sep, 2011 01:11 AM

    Abel de Beer's Avatar

    This might also be a nice addition to the discussion: Mediate non-visual view components

  16. 17 Posted by Kyle on 19 Sep, 2011 02:44 AM

    Kyle's Avatar

    Great info. in that post as well Stray, thanks!

  17. Kyle closed this discussion on 02 Oct, 2011 09:55 PM.

Comments are currently closed for this discussion. You can start a new one.